Integrating latest 47acbe8

This commit is contained in:
alexpete
2021-03-25 13:57:57 -07:00
parent 448c549698
commit 75dc720198
10312 changed files with 2711566 additions and 671451 deletions
@@ -0,0 +1,42 @@
/*
* 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 <AWSClientAuthModule.h>
#include <AWSClientAuthSystemComponent.h>
namespace AWSClientAuth
{
AWSClientAuthModule::AWSClientAuthModule()
: AZ::Module()
{
// Push results of [MyComponent]::CreateDescriptor() into m_descriptors here.
m_descriptors.insert(m_descriptors.end(), {
AWSClientAuthSystemComponent::CreateDescriptor()
});
}
/**
* Add required SystemComponents to the SystemEntity.
*/
AZ::ComponentTypeList AWSClientAuthModule::GetRequiredSystemComponents() const
{
return AZ::ComponentTypeList{
azrtti_typeid<AWSClientAuthSystemComponent>(),
};
}
}
// DO NOT MODIFY THIS LINE UNLESS YOU RENAME THE GEM
// The first parameter should be GemName_GemIdLower
// The second should be the fully qualified name of the class above
AZ_DECLARE_MODULE_CLASS(AWSClientAuth_c74f2756f5874c0d8d29646dfc9cb0ad, AWSClientAuth::AWSClientAuthModule)
@@ -0,0 +1,176 @@
/*
* 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 <AWSClientAuthSystemComponent.h>
#include <Authentication/AuthenticationProviderTypes.h>
#include <Authentication/AuthenticationNotificationBusBehaviorHandler.h>
#include <UserManagement/UserManagementNotificationBusBehaviorHandler.h>
#include <Authorization/AWSCognitoAuthorizationNotificationBusBehaviorHandler.h>
#include <Authorization/AWSCognitoAuthorizationController.h>
#include <Authorization/AWSCognitoAuthorizationTypes.h>
#include <AzCore/std/smart_ptr/make_shared.h>
#include <ResourceMapping/AWSResourceMappingBus.h>
#include <aws/cognito-identity/CognitoIdentityClient.h>
#include <aws/cognito-idp/CognitoIdentityProviderClient.h>
namespace AWSClientAuth
{
constexpr char SERIALIZE_COMPONENT_NAME[] = "AWSClientAuth";
void AWSClientAuthSystemComponent::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
serialize->Class<AWSClientAuthSystemComponent, AZ::Component>()->Version(0);
if (AZ::EditContext* ec = serialize->GetEditContext())
{
ec->Class<AWSClientAuthSystemComponent>("AWSClientAuth", "Provides Client Authentication and Authorization implementations")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("System"))
->Attribute(AZ::Edit::Attributes::AutoExpand, true);
}
AWSClientAuth::AWSCognitoProviderSetting::Reflect(*serialize);
AWSClientAuth::LWAProviderSetting::Reflect(*serialize);
AWSClientAuth::GoogleProviderSetting::Reflect(*serialize);
AWSClientAuth::CognitoAuthorizationSettings::Reflect(*serialize);
AWSClientAuth::AWSCognitoUserManagementSetting::Reflect(*serialize);
}
if (AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
{
behaviorContext->EBus<AuthenticationProviderRequestBus>("AuthenticationProviderRequestBus")
->Attribute(AZ::Script::Attributes::Category, SERIALIZE_COMPONENT_NAME)
->Event("Initialize", &AuthenticationProviderRequestBus::Events::Initialize)
->Event("IsSignedIn", &AuthenticationProviderRequestBus::Events::IsSignedIn)
->Event("GetAuthenticationTokens", &AuthenticationProviderRequestBus::Events::GetAuthenticationTokens)
->Event(
"PasswordGrantSingleFactorSignInAsync", &AuthenticationProviderRequestBus::Events::PasswordGrantSingleFactorSignInAsync)
->Event("DeviceCodeGrantSignInAsync", &AuthenticationProviderRequestBus::Events::DeviceCodeGrantSignInAsync)
->Event("DeviceCodeGrantConfirmSignInAsync", &AuthenticationProviderRequestBus::Events::DeviceCodeGrantConfirmSignInAsync)
->Event("RefreshTokensAsync", &AuthenticationProviderRequestBus::Events::RefreshTokensAsync)
->Event("GetTokensWithRefreshAsync", &AuthenticationProviderRequestBus::Events::GetTokensWithRefreshAsync)
->Event("SignOut", &AuthenticationProviderRequestBus::Events::SignOut);
behaviorContext->EBus<AWSCognitoAuthorizationRequestBus>("AWSCognitoAuthorizationRequestBus")
->Attribute(AZ::Script::Attributes::Category, SERIALIZE_COMPONENT_NAME)
->Event("Initialize", &AWSCognitoAuthorizationRequestBus::Events::Initialize)
->Event("Reset", &AWSCognitoAuthorizationRequestBus::Events::Reset)
->Event("GetIdentityId", &AWSCognitoAuthorizationRequestBus::Events::GetIdentityId)
->Event("HasPersistedLogins", &AWSCognitoAuthorizationRequestBus::Events::HasPersistedLogins)
->Event("RequestAWSCredentialsAsync", &AWSCognitoAuthorizationRequestBus::Events::RequestAWSCredentialsAsync);
behaviorContext->EBus<AWSCognitoUserManagementRequestBus>("AWSCognitoUserManagementRequestBus")
->Attribute(AZ::Script::Attributes::Category, SERIALIZE_COMPONENT_NAME)
->Event("Initialize", &AWSCognitoUserManagementRequestBus::Events::Initialize)
->Event("EmailSignUpAsync", &AWSCognitoUserManagementRequestBus::Events::EmailSignUpAsync)
->Event("PhoneSignUpAsync", &AWSCognitoUserManagementRequestBus::Events::PhoneSignUpAsync)
->Event("ConfirmSignUpAsync", &AWSCognitoUserManagementRequestBus::Events::ConfirmSignUpAsync)
->Event("ForgotPasswordAsync", &AWSCognitoUserManagementRequestBus::Events::ForgotPasswordAsync)
->Event("ConfirmForgotPasswordAsync", &AWSCognitoUserManagementRequestBus::Events::ConfirmForgotPasswordAsync)
->Event("EnableMFAAsync", &AWSCognitoUserManagementRequestBus::Events::EnableMFAAsync);
behaviorContext->EBus<AuthenticationProviderNotificationBus>("AuthenticationProviderNotificationBus")
->Handler<AuthenticationNotificationBusBehaviorHandler>();
behaviorContext->EBus<AWSCognitoUserManagementNotificationBus>("AWSCognitoUserManagementNotificationBus")
->Handler<UserManagementNotificationBusBehaviorHandler>();
behaviorContext->EBus<AWSCognitoAuthorizationNotificationBus>("AWSCognitoAuthorizationNotificationBus")
->Handler<AWSCognitoAuthorizationNotificationBusBehaviorHandler>();
}
}
void AWSClientAuthSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC_CE("AWSClientAuthService"));
}
void AWSClientAuthSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
{
incompatible.push_back(AZ_CRC_CE("AWSClientAuthService"));
}
void AWSClientAuthSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC_CE("AWSCoreService"));
}
void AWSClientAuthSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
AZ_UNUSED(dependent);
}
void AWSClientAuthSystemComponent::Init()
{
m_enabledProviderNames.push_back(ProviderNameEnum::AWSCognitoIDP);
// As this Gem depends on AWSCore, AWSCoreSystemComponent gets activated before AWSClientAuth and will miss the OnSDKInitialized
// notification if BusConnect is not in Init.
AWSCore::AWSCoreNotificationsBus::Handler::BusConnect();
}
void AWSClientAuthSystemComponent::Activate()
{
AZ::Interface<IAWSClientAuthRequests>::Register(this);
AWSClientAuthRequestBus::Handler::BusConnect();
// Objects below depend on bus above.
m_authenticationProviderManager = AZStd::make_unique<AuthenticationProviderManager>();
m_awsCognitoUserManagementController = AZStd::make_unique<AWSCognitoUserManagementController>();
m_awsCognitoAuthorizationController = AZStd::make_unique<AWSCognitoAuthorizationController>();
AWSCore::AWSCoreEditorRequestBus::Broadcast(&AWSCore::AWSCoreEditorRequests::SetAWSClientAuthEnabled);
}
void AWSClientAuthSystemComponent::Deactivate()
{
m_authenticationProviderManager.reset();
m_awsCognitoUserManagementController.reset();
m_awsCognitoAuthorizationController.reset();
AWSClientAuthRequestBus::Handler::BusDisconnect();
AWSCore::AWSCoreNotificationsBus::Handler::BusDisconnect();
AZ::Interface<IAWSClientAuthRequests>::Unregister(this);
m_cognitoIdentityProviderClient.reset();
m_cognitoIdentityClient.reset();
}
void AWSClientAuthSystemComponent::OnSDKInitialized()
{
Aws::Client::ClientConfiguration clientConfiguration;
AZStd::string region;
AWSCore::AWSResourceMappingRequestBus::BroadcastResult(region, &AWSCore::AWSResourceMappingRequests::GetDefaultRegion);
clientConfiguration.region = "us-west-2";
if (!region.empty())
{
clientConfiguration.region = region.c_str();
}
m_cognitoIdentityProviderClient =
std::make_shared<Aws::CognitoIdentityProvider::CognitoIdentityProviderClient>(clientConfiguration);
m_cognitoIdentityClient = std::make_shared<Aws::CognitoIdentity::CognitoIdentityClient>(clientConfiguration);
}
std::shared_ptr<Aws::CognitoIdentityProvider::CognitoIdentityProviderClient> AWSClientAuthSystemComponent::GetCognitoIDPClient()
{
return m_cognitoIdentityProviderClient;
}
std::shared_ptr<Aws::CognitoIdentity::CognitoIdentityClient> AWSClientAuthSystemComponent::GetCognitoIdentityClient()
{
return m_cognitoIdentityClient;
}
} // namespace AWSClientAuth
@@ -0,0 +1,254 @@
/*
* 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 <AzCore/std/smart_ptr/weak_ptr.h>
#include <AzCore/Jobs/JobFunction.h>
#include <Authentication/AWSCognitoAuthenticationProvider.h>
#include <Authentication/AuthenticationProviderTypes.h>
#include <Authentication/AuthenticationProviderBus.h>
#include <AWSClientAuthBus.h>
#include <AWSCoreBus.h>
#include <aws/cognito-idp/model/InitiateAuthRequest.h>
#include <aws/cognito-idp/model/InitiateAuthResult.h>
#include <aws/cognito-idp/model/RespondToAuthChallengeRequest.h>
#include <aws/cognito-idp/model/RespondToAuthChallengeResult.h>
#include <aws/cognito-idp/CognitoIdentityProviderClient.h>
#include <aws/cognito-idp/CognitoIdentityProviderErrors.h>
namespace AWSClientAuth
{
constexpr char COGNITO_IDP_SETTINGS_PATH[] = "/AWS/CognitoIDP";
constexpr char COGNITO_USERNAME_KEY[] = "USERNAME";
constexpr char COGNITO_PASSWORD_KEY[] = "PASSWORD";
constexpr char COGNITO_REFRESH_TOKEN_AUTHPARAM_KEY[] = "REFRESH_TOKEN";
constexpr char COGNITO_SMS_MFA_CODE_KEY[] = "SMS_MFA_CODE";
AWSCognitoAuthenticationProvider::AWSCognitoAuthenticationProvider()
{
m_settings = AZStd::make_unique<AWSCognitoProviderSetting>();
}
AWSCognitoAuthenticationProvider::~AWSCognitoAuthenticationProvider()
{
m_settings.reset();
}
bool AWSCognitoAuthenticationProvider::Initialize(AZStd::weak_ptr<AZ::SettingsRegistryInterface> settingsRegistry)
{
if (!settingsRegistry.lock()->GetObject(m_settings.get(), azrtti_typeid(m_settings.get()), COGNITO_IDP_SETTINGS_PATH))
{
AZ_Warning("AWSCognitoAuthenticationProvider", true, "Failed to get settings object for path %s", COGNITO_IDP_SETTINGS_PATH);
return false;
}
return true;
}
void AWSCognitoAuthenticationProvider::PasswordGrantSingleFactorSignInAsync(const AZStd::string& username, const AZStd::string& password)
{
InitiateAuthInternalAsync(username, password, [this](Aws::CognitoIdentityProvider::Model::InitiateAuthOutcome initiateAuthOutcome)
{
if (initiateAuthOutcome.IsSuccess())
{
Aws::CognitoIdentityProvider::Model::InitiateAuthResult initiateAuthResult{ initiateAuthOutcome.GetResult() };
if (initiateAuthResult.GetChallengeName() == Aws::CognitoIdentityProvider::Model::ChallengeNameType::NOT_SET)
{
Aws::CognitoIdentityProvider::Model::AuthenticationResultType authenticationResult = initiateAuthResult.GetAuthenticationResult();
UpdateTokens(authenticationResult);
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnPasswordGrantSingleFactorSignInSuccess
, m_authenticationTokens);
}
else
{
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnPasswordGrantSingleFactorSignInFail
, AZStd::string::format("Unexpected Challenge type: %s"
, Aws::CognitoIdentityProvider::Model::ChallengeNameTypeMapper::GetNameForChallengeNameType(initiateAuthResult.GetChallengeName()).c_str()));
}
}
else
{
Aws::Client::AWSError<Aws::CognitoIdentityProvider::CognitoIdentityProviderErrors> error = initiateAuthOutcome.GetError();
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnPasswordGrantSingleFactorSignInFail, error.GetMessage().c_str());
}
});
}
void AWSCognitoAuthenticationProvider::PasswordGrantMultiFactorSignInAsync(const AZStd::string& username, const AZStd::string& password)
{
InitiateAuthInternalAsync(username, password, [this](Aws::CognitoIdentityProvider::Model::InitiateAuthOutcome initiateAuthOutcome)
{
if (initiateAuthOutcome.IsSuccess())
{
Aws::CognitoIdentityProvider::Model::InitiateAuthResult initiateAuthResult{ initiateAuthOutcome.GetResult() };
if (initiateAuthResult.GetChallengeName() == Aws::CognitoIdentityProvider::Model::ChallengeNameType::SMS_MFA)
{
Aws::CognitoIdentityProvider::Model::AuthenticationResultType authenticationResult = initiateAuthResult.GetAuthenticationResult();
// Call on sign in success for MFA
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnPasswordGrantMultiFactorSignInSuccess);
m_session = initiateAuthResult.GetSession().c_str();
}
else
{
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnPasswordGrantMultiFactorSignInFail
, AZStd::string::format("Unexpected Challenge type: %s"
, Aws::CognitoIdentityProvider::Model::ChallengeNameTypeMapper::GetNameForChallengeNameType(initiateAuthResult.GetChallengeName()).c_str()));
}
}
else
{
Aws::Client::AWSError<Aws::CognitoIdentityProvider::CognitoIdentityProviderErrors> error = initiateAuthOutcome.GetError();
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnPasswordGrantMultiFactorSignInFail, error.GetMessage().c_str());
}
});
}
// Call RespondToAuthChallenge for Cognito authentication flow.
// Refer https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html.
void AWSCognitoAuthenticationProvider::PasswordGrantMultiFactorConfirmSignInAsync(const AZStd::string& username, const AZStd::string& confirmationCode)
{
std::shared_ptr<Aws::CognitoIdentityProvider::CognitoIdentityProviderClient> cognitoIdentityProviderClient =
AZ::Interface<IAWSClientAuthRequests>::Get()->GetCognitoIDPClient();
AZ::JobContext* jobContext = nullptr;
AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
AZ::Job* confirmSignInJob = AZ::CreateJobFunction([this, cognitoIdentityProviderClient, confirmationCode, username]()
{
// Set Request parameters for SMS Multi factor authentication.
// Note: Email MFA is no longer supported by Cognito, use SMS as MFA
Aws::CognitoIdentityProvider::Model::RespondToAuthChallengeRequest respondToAuthChallengeRequest;
respondToAuthChallengeRequest.SetClientId(m_settings->m_appClientId.c_str());
respondToAuthChallengeRequest.AddChallengeResponses(COGNITO_SMS_MFA_CODE_KEY, confirmationCode.c_str());
respondToAuthChallengeRequest.AddChallengeResponses(COGNITO_USERNAME_KEY, username.c_str());
respondToAuthChallengeRequest.SetChallengeName(Aws::CognitoIdentityProvider::Model::ChallengeNameType::SMS_MFA);
respondToAuthChallengeRequest.SetSession(m_session.c_str());
Aws::CognitoIdentityProvider::Model::RespondToAuthChallengeOutcome respondToAuthChallengeOutcome{ cognitoIdentityProviderClient->RespondToAuthChallenge(respondToAuthChallengeRequest) };
if (respondToAuthChallengeOutcome.IsSuccess())
{
Aws::CognitoIdentityProvider::Model::RespondToAuthChallengeResult respondToAuthChallengeResult{ respondToAuthChallengeOutcome.GetResult() };
if (respondToAuthChallengeResult.GetChallengeName() == Aws::CognitoIdentityProvider::Model::ChallengeNameType::NOT_SET)
{
Aws::CognitoIdentityProvider::Model::AuthenticationResultType authenticationResult = respondToAuthChallengeResult.GetAuthenticationResult();
UpdateTokens(authenticationResult);
AuthenticationProviderNotificationBus::Broadcast(
&AuthenticationProviderNotifications::OnPasswordGrantMultiFactorConfirmSignInSuccess, m_authenticationTokens);
}
}
else
{
Aws::Client::AWSError<Aws::CognitoIdentityProvider::CognitoIdentityProviderErrors> error = respondToAuthChallengeOutcome.GetError();
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnPasswordGrantMultiFactorConfirmSignInFail, error.GetMessage().c_str());
}
}, true, jobContext);
confirmSignInJob->Start();
}
void AWSCognitoAuthenticationProvider::DeviceCodeGrantSignInAsync()
{
AZ_Assert(true, "Not supported");
}
void AWSCognitoAuthenticationProvider::DeviceCodeGrantConfirmSignInAsync()
{
AZ_Assert(true, "Not supported");
}
void AWSCognitoAuthenticationProvider::RefreshTokensAsync()
{
std::shared_ptr<Aws::CognitoIdentityProvider::CognitoIdentityProviderClient> cognitoIdentityProviderClient =
AZ::Interface<IAWSClientAuthRequests>::Get()->GetCognitoIDPClient();
AZ::JobContext* jobContext = nullptr;
AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
AZ::Job* initiateAuthJob = AZ::CreateJobFunction([this, cognitoIdentityProviderClient]()
{
// Set Request parameters.
Aws::CognitoIdentityProvider::Model::InitiateAuthRequest initiateAuthRequest;
initiateAuthRequest.SetClientId(m_settings->m_appClientId.c_str());
initiateAuthRequest.SetAuthFlow(Aws::CognitoIdentityProvider::Model::AuthFlowType::REFRESH_TOKEN_AUTH);
// Set username and password for Password grant/ Initiate Auth flow.
Aws::Map<Aws::String, Aws::String> authParameters
{
{COGNITO_REFRESH_TOKEN_AUTHPARAM_KEY, GetAuthenticationTokens().GetRefreshToken().c_str()}
};
initiateAuthRequest.SetAuthParameters(authParameters);
Aws::CognitoIdentityProvider::Model::InitiateAuthOutcome initiateAuthOutcome{ cognitoIdentityProviderClient->InitiateAuth(initiateAuthRequest) };
if (initiateAuthOutcome.IsSuccess())
{
Aws::CognitoIdentityProvider::Model::InitiateAuthResult initiateAuthResult{ initiateAuthOutcome.GetResult() };
if (initiateAuthResult.GetChallengeName() == Aws::CognitoIdentityProvider::Model::ChallengeNameType::NOT_SET)
{
Aws::CognitoIdentityProvider::Model::AuthenticationResultType authenticationResult = initiateAuthResult.GetAuthenticationResult();
UpdateTokens(authenticationResult);
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnRefreshTokensSuccess, m_authenticationTokens);
}
else
{
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnRefreshTokensFail
, AZStd::string::format("Unexpected Challenge type: %s"
, Aws::CognitoIdentityProvider::Model::ChallengeNameTypeMapper::GetNameForChallengeNameType(initiateAuthResult.GetChallengeName()).c_str()));
}
}
else
{
Aws::Client::AWSError<Aws::CognitoIdentityProvider::CognitoIdentityProviderErrors> error = initiateAuthOutcome.GetError();
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnRefreshTokensFail, error.GetMessage().c_str());
}
}, true, jobContext);
initiateAuthJob->Start();
}
// Call InitiateAuth for Cognito authentication flow.
// Refer https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html.
void AWSCognitoAuthenticationProvider::InitiateAuthInternalAsync(const AZStd::string& username, const AZStd::string& password
, AZStd::function<void(Aws::CognitoIdentityProvider::Model::InitiateAuthOutcome outcome)> outcomeCallback)
{
std::shared_ptr<Aws::CognitoIdentityProvider::CognitoIdentityProviderClient> cognitoIdentityProviderClient =
AZ::Interface<IAWSClientAuthRequests>::Get()->GetCognitoIDPClient();
AZ::JobContext* jobContext = nullptr;
AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
AZ::Job* initiateAuthJob = AZ::CreateJobFunction([this, cognitoIdentityProviderClient, username, password, outcomeCallback]()
{
// Set Request parameters.
Aws::CognitoIdentityProvider::Model::InitiateAuthRequest initiateAuthRequest;
initiateAuthRequest.SetClientId(m_settings->m_appClientId.c_str());
initiateAuthRequest.SetAuthFlow(Aws::CognitoIdentityProvider::Model::AuthFlowType::USER_PASSWORD_AUTH);
// Set username and password for Password grant/ Initiate Auth flow.
Aws::Map<Aws::String, Aws::String> authParameters
{
{COGNITO_USERNAME_KEY, username.c_str()},
{COGNITO_PASSWORD_KEY, password.c_str()}
};
initiateAuthRequest.SetAuthParameters(authParameters);
Aws::CognitoIdentityProvider::Model::InitiateAuthOutcome initiateAuthOutcome{ cognitoIdentityProviderClient->InitiateAuth(initiateAuthRequest) };
outcomeCallback(initiateAuthOutcome);
}, true, jobContext);
initiateAuthJob->Start();
}
void AWSCognitoAuthenticationProvider::UpdateTokens(const Aws::CognitoIdentityProvider::Model::AuthenticationResultType& authenticationResult)
{
m_authenticationTokens = AuthenticationTokens(authenticationResult.GetAccessToken().c_str(), authenticationResult.GetRefreshToken().c_str(),
authenticationResult.GetIdToken().c_str(), ProviderNameEnum::AWSCognitoIDP,
authenticationResult.GetExpiresIn());
}
} // namespace AWSClientAuth
@@ -0,0 +1,28 @@
/*
* 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 <Authentication/AuthenticationProviderInterface.h>
namespace AWSClientAuth
{
AuthenticationTokens AuthenticationProviderInterface::GetAuthenticationTokens()
{
return m_authenticationTokens;
}
void AuthenticationProviderInterface::SignOut()
{
m_authenticationTokens = AuthenticationTokens();
}
} // namespace AWSClientAuth
@@ -0,0 +1,185 @@
/*
* 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 <AzCore/std/smart_ptr/make_shared.h>
#include <AzCore/Settings/SettingsRegistryImpl.h>
#include <Authentication/AuthenticationProviderTypes.h>
#include <Authentication/AWSCognitoAuthenticationProvider.h>
#include <Authentication/LWAAuthenticationProvider.h>
#include <Authentication/GoogleAuthenticationProvider.h>
#include <Authentication/AuthenticationProviderManager.h>
namespace AWSClientAuth
{
AuthenticationProviderManager::AuthenticationProviderManager()
{
AZ::Interface<IAuthenticationProviderRequests>::Register(this);
AuthenticationProviderRequestBus::Handler::BusConnect();
}
AuthenticationProviderManager::~AuthenticationProviderManager()
{
ResetProviders();
m_settingsRegistry.reset();
AuthenticationProviderRequestBus::Handler::BusDisconnect();
AZ::Interface<IAuthenticationProviderRequests>::Unregister(this);
}
bool AuthenticationProviderManager::Initialize(const AZStd::vector<ProviderNameEnum>& providerNames, const AZStd::string& settingsRegistryPath)
{
ResetProviders();
m_settingsRegistry.reset();
m_settingsRegistry = AZStd::make_shared<AZ::SettingsRegistryImpl>();
if (!m_settingsRegistry->MergeSettingsFile(settingsRegistryPath, AZ::SettingsRegistryInterface::Format::JsonMergePatch))
{
AZ_Error("AuthenticationProviderManager", true, "Error merging settings registry for path: %s", settingsRegistryPath.c_str());
return false;
}
bool initializeSuccess = true;
for (auto providerName : providerNames)
{
m_authenticationProvidersMap[providerName] = CreateAuthenticationProviderObject(providerName);
initializeSuccess = initializeSuccess && m_authenticationProvidersMap[providerName]->Initialize(m_settingsRegistry);
}
return initializeSuccess;
}
void AuthenticationProviderManager::PasswordGrantSingleFactorSignInAsync(const ProviderNameEnum& providerName, const AZStd::string& username, const AZStd::string& password)
{
if (IsProviderInitialized(providerName))
{
m_authenticationProvidersMap[providerName]->PasswordGrantSingleFactorSignInAsync(username, password);
}
}
void AuthenticationProviderManager::PasswordGrantMultiFactorSignInAsync(const ProviderNameEnum& providerName, const AZStd::string& username, const AZStd::string& password)
{
if (IsProviderInitialized(providerName))
{
m_authenticationProvidersMap[providerName]->PasswordGrantMultiFactorSignInAsync(username, password);
}
}
void AuthenticationProviderManager::PasswordGrantMultiFactorConfirmSignInAsync(const ProviderNameEnum& providerName, const AZStd::string& username, const AZStd::string& confirmationCode)
{
if (IsProviderInitialized(providerName))
{
m_authenticationProvidersMap[providerName]->PasswordGrantMultiFactorConfirmSignInAsync(username, confirmationCode);
}
}
void AuthenticationProviderManager::DeviceCodeGrantSignInAsync(const ProviderNameEnum& providerName)
{
if (IsProviderInitialized(providerName))
{
m_authenticationProvidersMap[providerName]->DeviceCodeGrantSignInAsync();
}
}
void AuthenticationProviderManager::DeviceCodeGrantConfirmSignInAsync(const ProviderNameEnum& providerName)
{
if (IsProviderInitialized(providerName))
{
m_authenticationProvidersMap[providerName]->DeviceCodeGrantConfirmSignInAsync();
}
}
void AuthenticationProviderManager::RefreshTokensAsync(const ProviderNameEnum& providerName)
{
if (IsProviderInitialized(providerName))
{
m_authenticationProvidersMap[providerName]->RefreshTokensAsync();
}
}
void AuthenticationProviderManager::GetTokensWithRefreshAsync(const ProviderNameEnum& providerName)
{
if (!IsProviderInitialized(providerName))
{
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnRefreshTokensFail
, "Provider is not initialized");
}
AuthenticationTokens tokens = m_authenticationProvidersMap[providerName]->GetAuthenticationTokens();
if (tokens.AreTokensValid())
{
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnRefreshTokensSuccess, tokens);
}
else
{
m_authenticationProvidersMap[providerName]->RefreshTokensAsync();
}
}
bool AuthenticationProviderManager::IsSignedIn(const ProviderNameEnum& providerName)
{
if (IsProviderInitialized(providerName))
{
return m_authenticationProvidersMap[providerName]->GetAuthenticationTokens().AreTokensValid();
}
return false;
}
bool AuthenticationProviderManager::SignOut(const ProviderNameEnum& providerName)
{
if (IsProviderInitialized(providerName))
{
m_authenticationProvidersMap[providerName]->SignOut();
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnSignOut, providerName);
return true;
}
return false;
}
AuthenticationTokens AuthenticationProviderManager::GetAuthenticationTokens(const ProviderNameEnum& providerName)
{
return m_authenticationProvidersMap[providerName]->GetAuthenticationTokens();
}
AZStd::unique_ptr<AuthenticationProviderInterface> AuthenticationProviderManager::CreateAuthenticationProviderObject(const ProviderNameEnum& providerName)
{
switch (providerName)
{
case ProviderNameEnum::AWSCognitoIDP:
return AZStd::make_unique<AWSCognitoAuthenticationProvider>();
case ProviderNameEnum::LoginWithAmazon:
return AZStd::make_unique<LWAAuthenticationProvider>();
case ProviderNameEnum::Google:
return AZStd::make_unique<GoogleAuthenticationProvider>();
default:
return nullptr;
}
}
bool AuthenticationProviderManager::IsProviderInitialized(const ProviderNameEnum& providerName)
{
bool ret = m_authenticationProvidersMap.contains(providerName);
AZ_Assert(ret, "ProviderName enum %i not initialized. Please call initialize first");
return ret;
}
void AuthenticationProviderManager::ResetProviders()
{
for (auto& [providerName, providerInterface] : m_authenticationProvidersMap)
{
providerInterface.reset();
}
}
} // namespace AWSClientAuth
@@ -0,0 +1,82 @@
/*
* 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 <Authentication/AuthenticationTokens.h>
namespace AWSClientAuth
{
//! Used to share authentication tokens to caller and to AWSCognitoAuthorizationController.
AuthenticationTokens::AuthenticationTokens()
{
m_tokensExpireTimeStamp = AZStd::chrono::system_clock::time_point::min();
m_providerName = ProviderNameEnum::None;
}
AuthenticationTokens::AuthenticationTokens(const AuthenticationTokens& other)
{
m_accessToken = other.m_accessToken;
m_refreshToken = other.m_refreshToken;
m_openIdToken = other.m_openIdToken;
m_providerName = other.m_providerName;
m_tokensExpireTimeSeconds = other.m_tokensExpireTimeSeconds;
m_tokensExpireTimeStamp = other.m_tokensExpireTimeStamp;
}
AuthenticationTokens::AuthenticationTokens(
const AZStd::string& accessToken, const AZStd::string& refreshToken, const AZStd::string& openidToken, const ProviderNameEnum& providerName, int tokensExpireTimeSeconds)
{
m_accessToken = accessToken;
m_refreshToken = refreshToken;
m_openIdToken = openidToken;
m_providerName = providerName;
m_tokensExpireTimeSeconds = tokensExpireTimeSeconds;
m_tokensExpireTimeStamp = AZStd::chrono::system_clock::now() + AZStd::chrono::seconds(tokensExpireTimeSeconds);
}
//! Compares current time stamp to expired time stamp.
//! @return True if current TS less than expiry TS.
bool AuthenticationTokens::AreTokensValid() const
{
return AZStd::chrono::system_clock::now() < m_tokensExpireTimeStamp;
}
//! @return Open id token from authentication.
AZStd::string AuthenticationTokens::GetOpenIdToken() const
{
return m_openIdToken;
}
//! @return Access token from authentication.
AZStd::string AuthenticationTokens::GetAccessToken() const
{
return m_accessToken;
}
//! @return Refresh token from authentication.
AZStd::string AuthenticationTokens::GetRefreshToken() const
{
return m_refreshToken;
}
//! @return Provide name for the tokens.
ProviderNameEnum AuthenticationTokens::GetProviderName() const
{
return m_providerName;
}
//! @return Expiration time in seconds.
int AuthenticationTokens::GetTokensExpireTimeSeconds() const
{
return m_tokensExpireTimeSeconds;
}
} // namespace AWSClientAuth
@@ -0,0 +1,172 @@
/*
* 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 <AzCore/std/smart_ptr/make_shared.h>
#include <Authentication/GoogleAuthenticationProvider.h>
#include <Authentication/AuthenticationProviderBus.h>
#include <Authentication/OAuthConstants.h>
#include <HttpRequestor/HttpRequestorBus.h>
#include <HttpRequestor/HttpTypes.h>
#include <aws/core/http/HttpResponse.h>
namespace AWSClientAuth
{
constexpr char GOOGLE_SETTINGS_PATH[] = "/AWS/Google";
constexpr char GOOGLE_VERIFICATION_URL_RESPONSE_KEY[] = "verification_url";
GoogleAuthenticationProvider::GoogleAuthenticationProvider()
{
m_settings = AZStd::make_unique<GoogleProviderSetting>();
}
GoogleAuthenticationProvider::~GoogleAuthenticationProvider()
{
m_settings.reset();
}
bool GoogleAuthenticationProvider::Initialize(AZStd::weak_ptr<AZ::SettingsRegistryInterface> settingsRegistry)
{
if (!settingsRegistry.lock()->GetObject(m_settings.get(), azrtti_typeid(m_settings.get()), GOOGLE_SETTINGS_PATH))
{
AZ_Warning("AWSCognitoAuthenticationProvider", true, "Failed to get Google settings object for path %s", GOOGLE_SETTINGS_PATH);
return false;
}
return true;
}
void GoogleAuthenticationProvider::PasswordGrantSingleFactorSignInAsync(const AZStd::string& username, const AZStd::string& password)
{
AZ_UNUSED(username);
AZ_UNUSED(password);
AZ_Assert(true, "Not supported");
}
void GoogleAuthenticationProvider::PasswordGrantMultiFactorSignInAsync(const AZStd::string& username, const AZStd::string& password)
{
AZ_UNUSED(username);
AZ_UNUSED(password);
AZ_Assert(true, "Not supported");
}
void GoogleAuthenticationProvider::PasswordGrantMultiFactorConfirmSignInAsync(const AZStd::string& username, const AZStd::string& confirmationCode)
{
AZ_UNUSED(username);
AZ_UNUSED(confirmationCode);
AZ_Assert(true, "Not supported");
}
// Call Google authentication provider device code end point.
// Refer https://developers.google.com/identity/protocols/oauth2/limited-input-device#step-1:-request-device-and-user-codes.
void GoogleAuthenticationProvider::DeviceCodeGrantSignInAsync()
{
AZStd::string body = AZStd::string::format("%s=%s&%s=%s", OAUTH_CLIENT_ID_BODY_KEY, m_settings->m_appClientId.c_str()
, OAUTH_SCOPE_BODY_KEY, OAUTH_SCOPE_BODY_VALUE);
// Set headers and body for device sign in http requests.
AZStd::map<AZStd::string, AZStd::string> headers;
headers[OAUTH_CONTENT_TYPE_HEADER_KEY] = OAUTH_CONTENT_TYPE_HEADER_VALUE;
headers[OAUTH_CONTENT_LENGTH_HEADER_KEY] = AZStd::to_string(body.length());
HttpRequestor::HttpRequestorRequestBus::Broadcast(&HttpRequestor::HttpRequestorRequests::AddRequestWithHeadersAndBody, m_settings->m_oAuthCodeURL
, Aws::Http::HttpMethod::HTTP_POST, headers, body
, [this](const Aws::Utils::Json::JsonView& jsonView, Aws::Http::HttpResponseCode responseCode)
{
if (responseCode == Aws::Http::HttpResponseCode::OK)
{
m_cachedDeviceCode = jsonView.GetString(OAUTH_DEVICE_CODE_BODY_KEY).c_str();
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnDeviceCodeGrantSignInSuccess
, jsonView.GetString(OAUTH_USER_CODE_RESPONSE_KEY).c_str(), jsonView.GetString(GOOGLE_VERIFICATION_URL_RESPONSE_KEY).c_str()
, jsonView.GetInteger(OAUTH_EXPIRES_IN_RESPONSE_KEY));
}
else
{
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnDeviceCodeGrantSignInFail
, jsonView.GetString(OAUTH_ERROR_RESPONSE_KEY).c_str());
}
}
);
}
// Call Google authentication provider OAuth tokens endpoint
// Refer https://developers.google.com/identity/protocols/oauth2/limited-input-device#step-4:-poll-googles-authorization-server.
void GoogleAuthenticationProvider::DeviceCodeGrantConfirmSignInAsync()
{
// Set headers and body for device confirm sign in http requests.
AZStd::map<AZStd::string, AZStd::string> headers;
AZStd::string body = AZStd::string::format("%s=%s&%s=%s&%s=%s&%s=%s", OAUTH_CLIENT_ID_BODY_KEY, m_settings->m_appClientId.c_str()
, OAUTH_CLIENT_SECRET_BODY_KEY, m_settings->m_clientSecret.c_str(), OAUTH_DEVICE_CODE_BODY_KEY, m_cachedDeviceCode.c_str()
, OAUTH_GRANT_TYPE_BODY_KEY, m_settings->m_grantType.c_str());
headers[OAUTH_CONTENT_TYPE_HEADER_KEY] = OAUTH_CONTENT_TYPE_HEADER_VALUE;
headers[OAUTH_CONTENT_LENGTH_HEADER_KEY] = AZStd::to_string(body.length());
HttpRequestor::HttpRequestorRequestBus::Broadcast(&HttpRequestor::HttpRequestorRequests::AddRequestWithHeadersAndBody, m_settings->m_oAuthTokensURL
, Aws::Http::HttpMethod::HTTP_POST, headers, body
, [this](const Aws::Utils::Json::JsonView& jsonView, Aws::Http::HttpResponseCode responseCode)
{
if (responseCode == Aws::Http::HttpResponseCode::OK)
{
UpdateTokens(jsonView);
AuthenticationProviderNotificationBus::Broadcast(
&AuthenticationProviderNotifications::OnDeviceCodeGrantConfirmSignInSuccess, m_authenticationTokens);
}
else
{
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnDeviceCodeGrantConfirmSignInFail
, jsonView.GetString(OAUTH_ERROR_RESPONSE_KEY).c_str());
}
}
);
}
// Call Google authentication provider OAuth tokens endpoint
// Refer https://developers.google.com/identity/protocols/oauth2/limited-input-device#offline.
void GoogleAuthenticationProvider::RefreshTokensAsync()
{
AZStd::map<AZStd::string, AZStd::string> headers;
AZStd::string body = AZStd::string::format("%s=%s&%s=%s&%s=%s&%s=%s", OAUTH_CLIENT_ID_BODY_KEY, m_settings->m_appClientId.c_str()
, OAUTH_CLIENT_SECRET_BODY_KEY, m_settings->m_clientSecret.c_str()
, OAUTH_GRANT_TYPE_BODY_KEY, OAUTH_REFRESH_TOKEN_BODY_VALUE, OAUTH_REFRESH_TOKEN_BODY_KEY, m_authenticationTokens.GetRefreshToken().c_str());
headers[OAUTH_CONTENT_TYPE_HEADER_KEY] = OAUTH_CONTENT_TYPE_HEADER_VALUE;
headers[OAUTH_CONTENT_LENGTH_HEADER_KEY] = AZStd::to_string(body.length());
HttpRequestor::HttpRequestorRequestBus::Broadcast(&HttpRequestor::HttpRequestorRequests::AddRequestWithHeadersAndBody, m_settings->m_oAuthTokensURL
, Aws::Http::HttpMethod::HTTP_POST, headers, body
, [this](const Aws::Utils::Json::JsonView& jsonView, Aws::Http::HttpResponseCode responseCode)
{
if (responseCode == Aws::Http::HttpResponseCode::OK)
{
UpdateTokens(jsonView);
AuthenticationProviderNotificationBus::Broadcast(
&AuthenticationProviderNotifications::OnRefreshTokensSuccess, m_authenticationTokens);
}
else
{
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnRefreshTokensFail
, jsonView.GetString(OAUTH_ERROR_RESPONSE_KEY).c_str());
}
}
);
}
void GoogleAuthenticationProvider::UpdateTokens(const Aws::Utils::Json::JsonView& jsonView)
{
m_authenticationTokens = AuthenticationTokens(jsonView.GetString(OAUTH_ACCESS_TOKEN_RESPONSE_KEY).c_str(),
jsonView.GetString(OAUTH_REFRESH_TOKEN_RESPONSE_KEY).c_str() ,jsonView.GetString(OAUTH_ID_TOKEN_RESPONSE_KEY).c_str(), ProviderNameEnum::Google
, jsonView.GetInteger(OAUTH_EXPIRES_IN_RESPONSE_KEY));
}
} // namespace AWSClientAuth
@@ -0,0 +1,173 @@
/*
* 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 <AzCore/std/smart_ptr/make_shared.h>
#include <Authentication/LWAAuthenticationProvider.h>
#include <Authentication/AuthenticationProviderBus.h>
#include <Authentication/OAuthConstants.h>
#include <HttpRequestor/HttpRequestorBus.h>
#include <HttpRequestor/HttpTypes.h>
#include <aws/core/http/HttpResponse.h>
namespace AWSClientAuth
{
constexpr char LWA_SETTINGS_PATH[] = "/AWS/LoginWithAmazon";
constexpr char LWA_VERIFICATION_URL_RESPONSE_KEY[] = "verification_uri";
LWAAuthenticationProvider::LWAAuthenticationProvider()
{
m_settings = AZStd::make_unique<LWAProviderSetting>();
}
LWAAuthenticationProvider::~LWAAuthenticationProvider()
{
m_settings.reset();
}
bool LWAAuthenticationProvider::Initialize(AZStd::weak_ptr<AZ::SettingsRegistryInterface> settingsRegistry)
{
if (!settingsRegistry.lock()->GetObject(m_settings.get(), azrtti_typeid(m_settings.get()), LWA_SETTINGS_PATH))
{
AZ_Warning("AWSCognitoAuthenticationProvider", true, "Failed to get login with Amazon settings object for path %s", LWA_SETTINGS_PATH);
return false;
}
return true;
}
void LWAAuthenticationProvider::PasswordGrantSingleFactorSignInAsync(const AZStd::string& username, const AZStd::string& password)
{
AZ_UNUSED(username);
AZ_UNUSED(password);
AZ_Assert(true, "Not supported");
}
void LWAAuthenticationProvider::PasswordGrantMultiFactorSignInAsync(const AZStd::string& username, const AZStd::string& password)
{
AZ_UNUSED(username);
AZ_UNUSED(password);
AZ_Assert(true, "Not supported");
}
void LWAAuthenticationProvider::PasswordGrantMultiFactorConfirmSignInAsync(const AZStd::string& username, const AZStd::string& confirmationCode)
{
AZ_UNUSED(username);
AZ_UNUSED(confirmationCode);
AZ_Assert(true, "Not supported");
}
// Call LWA authentication provider device code end point.
// Refer https://developer.amazon.com/docs/login-with-amazon/retrieve-code-other-platforms-cbl-docs.html.
void LWAAuthenticationProvider::DeviceCodeGrantSignInAsync()
{
// Set headers and body for device sign in http requests.
AZStd::string body = AZStd::string::format("%s=%s&%s=%s&%s=%s", OAUTH_RESPONSE_TYPE_BODY_KEY, m_settings->m_responseType.c_str()
, OAUTH_CLIENT_ID_BODY_KEY, m_settings->m_appClientId.c_str(), OAUTH_SCOPE_BODY_KEY, OAUTH_SCOPE_BODY_VALUE);
AZStd::map<AZStd::string, AZStd::string> headers;
headers[OAUTH_CONTENT_TYPE_HEADER_KEY] = OAUTH_CONTENT_TYPE_HEADER_VALUE;
headers[OAUTH_CONTENT_LENGTH_HEADER_KEY] = AZStd::to_string(body.length());
HttpRequestor::HttpRequestorRequestBus::Broadcast(&HttpRequestor::HttpRequestorRequests::AddRequestWithHeadersAndBody, m_settings->m_oAuthCodeURL
, Aws::Http::HttpMethod::HTTP_POST, headers, body
, [this](const Aws::Utils::Json::JsonView& jsonView, Aws::Http::HttpResponseCode responseCode)
{
if (responseCode == Aws::Http::HttpResponseCode::OK)
{
m_cachedUserCode = jsonView.GetString(OAUTH_USER_CODE_RESPONSE_KEY).c_str();
m_cachedDeviceCode = jsonView.GetString(OAUTH_DEVICE_CODE_BODY_KEY).c_str();
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnDeviceCodeGrantSignInSuccess
, jsonView.GetString(OAUTH_USER_CODE_RESPONSE_KEY).c_str()
, jsonView.GetString(LWA_VERIFICATION_URL_RESPONSE_KEY).c_str()
, jsonView.GetInteger(OAUTH_EXPIRES_IN_RESPONSE_KEY));
}
else
{
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnDeviceCodeGrantSignInFail
, jsonView.GetString(OAUTH_ERROR_RESPONSE_KEY).c_str());
}
}
);
}
// Call LWA authentication provider OAuth tokens endpoint
// Refer https://developer.amazon.com/docs/login-with-amazon/retrieve-token-other-platforms-cbl-docs.html
void LWAAuthenticationProvider::DeviceCodeGrantConfirmSignInAsync()
{
// Set headers and body for device confirm sign in http requests.
AZStd::string body = AZStd::string::format("%s=%s&%s=%s&%s=%s", OAUTH_USER_CODE_RESPONSE_KEY, m_cachedUserCode.c_str()
, OAUTH_GRANT_TYPE_BODY_KEY, m_settings->m_grantType.c_str(), OAUTH_DEVICE_CODE_BODY_KEY, m_cachedDeviceCode.c_str());
AZStd::map<AZStd::string, AZStd::string> headers;
headers[OAUTH_CONTENT_TYPE_HEADER_KEY] = OAUTH_CONTENT_TYPE_HEADER_VALUE;
headers[OAUTH_CONTENT_LENGTH_HEADER_KEY] = AZStd::to_string(body.length());
HttpRequestor::HttpRequestorRequestBus::Broadcast(&HttpRequestor::HttpRequestorRequests::AddRequestWithHeadersAndBody, m_settings->m_oAuthTokensURL
, Aws::Http::HttpMethod::HTTP_POST, headers, body
, [this](const Aws::Utils::Json::JsonView& jsonView, Aws::Http::HttpResponseCode responseCode)
{
if (responseCode == Aws::Http::HttpResponseCode::OK)
{
// Id and access token are the same.
UpdateTokens(jsonView);
AuthenticationProviderNotificationBus::Broadcast(
&AuthenticationProviderNotifications::OnDeviceCodeGrantConfirmSignInSuccess, m_authenticationTokens);
m_cachedUserCode = "";
m_cachedDeviceCode = "";
}
else
{
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnDeviceCodeGrantConfirmSignInFail
, jsonView.GetString("error").c_str());
}
}
);
}
void LWAAuthenticationProvider::RefreshTokensAsync()
{
// Set headers and body for device confirm sign in http requests.
AZStd::string body = AZStd::string::format("%s=%s&%s=%s&%s=%s", OAUTH_CLIENT_ID_BODY_KEY, m_settings->m_appClientId.c_str(), OAUTH_GRANT_TYPE_BODY_KEY,
OAUTH_REFRESH_TOKEN_BODY_VALUE, OAUTH_REFRESH_TOKEN_BODY_KEY, m_authenticationTokens.GetRefreshToken().c_str());
AZStd::map<AZStd::string, AZStd::string> headers;
headers[OAUTH_CONTENT_TYPE_HEADER_KEY] = OAUTH_CONTENT_TYPE_HEADER_VALUE;
headers[OAUTH_CONTENT_LENGTH_HEADER_KEY] = AZStd::to_string(body.length());
HttpRequestor::HttpRequestorRequestBus::Broadcast(&HttpRequestor::HttpRequestorRequests::AddRequestWithHeadersAndBody, m_settings->m_oAuthTokensURL
, Aws::Http::HttpMethod::HTTP_POST, headers, body
, [this](const Aws::Utils::Json::JsonView& jsonView, Aws::Http::HttpResponseCode responseCode)
{
if (responseCode == Aws::Http::HttpResponseCode::OK)
{
// Id and access token are the same.
UpdateTokens(jsonView);
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnRefreshTokensSuccess, m_authenticationTokens);
}
else
{
AuthenticationProviderNotificationBus::Broadcast(&AuthenticationProviderNotifications::OnRefreshTokensFail
, jsonView.GetString("error").c_str());
}
}
);
}
void LWAAuthenticationProvider::UpdateTokens(const Aws::Utils::Json::JsonView& jsonView)
{
// For Login with Amazon openId and access tokens are the same.
m_authenticationTokens = AuthenticationTokens(jsonView.GetString(OAUTH_ACCESS_TOKEN_RESPONSE_KEY).c_str(), jsonView.GetString(OAUTH_REFRESH_TOKEN_RESPONSE_KEY).c_str(),
jsonView.GetString(OAUTH_ACCESS_TOKEN_RESPONSE_KEY).c_str(), ProviderNameEnum::LoginWithAmazon
, jsonView.GetInteger(OAUTH_EXPIRES_IN_RESPONSE_KEY));
}
} // namespace AWSClientAuth
@@ -0,0 +1,90 @@
/*
* 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 <Authorization/AWSClientAuthPersistentCognitoIdentityProvider.h>
namespace AWSClientAuth
{
AWSClientAuthPersistentCognitoIdentityProvider::~AWSClientAuthPersistentCognitoIdentityProvider()
{
m_logins.clear();
m_awsAccountId = "";
m_identityPoolId = "";
m_identityId = "";
m_identityIdUpdatedCallback = nullptr;
m_loginsUpdatedCallback = nullptr;
}
void AWSClientAuthPersistentCognitoIdentityProvider::Initialize(const Aws::String& awsAccountId, const Aws::String& identityPoolId)
{
m_identityPoolId = identityPoolId;
m_awsAccountId = awsAccountId;
}
bool AWSClientAuthPersistentCognitoIdentityProvider::HasIdentityId() const
{
return !m_identityId.empty();
}
bool AWSClientAuthPersistentCognitoIdentityProvider::HasLogins() const
{
return m_logins.size() > 0;
}
Aws::String AWSClientAuthPersistentCognitoIdentityProvider::GetIdentityId() const
{
return m_identityId;
}
Aws::Map<Aws::String, Aws::Auth::LoginAccessTokens> AWSClientAuthPersistentCognitoIdentityProvider::GetLogins()
{
return m_logins;
}
Aws::String AWSClientAuthPersistentCognitoIdentityProvider::GetAccountId() const
{
return m_awsAccountId;
}
Aws::String AWSClientAuthPersistentCognitoIdentityProvider::GetIdentityPoolId() const
{
return m_identityPoolId;
}
void AWSClientAuthPersistentCognitoIdentityProvider::PersistIdentityId(const Aws::String& identityId)
{
m_identityId = identityId;
if (m_identityIdUpdatedCallback)
{
m_identityIdUpdatedCallback(*this);
}
}
void AWSClientAuthPersistentCognitoIdentityProvider::PersistLogins(const Aws::Map<Aws::String, Aws::Auth::LoginAccessTokens>& logins)
{
m_logins = logins;
if (m_loginsUpdatedCallback)
{
m_loginsUpdatedCallback(*this);
}
}
void AWSClientAuthPersistentCognitoIdentityProvider::RemoveLogin(const Aws::String& key)
{
m_logins.erase(key);
if (m_loginsUpdatedCallback)
{
m_loginsUpdatedCallback(*this);
}
}
} // namespace AWSClientAuth
@@ -0,0 +1,276 @@
/*
* 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 <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 COGNITO_AUTHORIZATION_SETTINGS_PATH[] = "/AWS/CognitoIdentityPool";
AWSCognitoAuthorizationController::AWSCognitoAuthorizationController()
{
AZ::Interface<IAWSCognitoAuthorizationRequests>::Register(this);
AWSCognitoAuthorizationRequestBus::Handler::BusConnect();
AuthenticationProviderNotificationBus::Handler::BusConnect();
AWSCore::AWSCredentialRequestBus::Handler::BusConnect();
m_settings = AZStd::make_unique<CognitoAuthorizationSettings>();
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();
m_settings.reset();
AWSCore::AWSCredentialRequestBus::Handler::BusDisconnect();
AuthenticationProviderNotificationBus::Handler::BusDisconnect();
AWSCognitoAuthorizationRequestBus::Handler::BusDisconnect();
AZ::Interface<IAWSCognitoAuthorizationRequests>::Unregister(this);
}
bool AWSCognitoAuthorizationController::Initialize(const AZStd::string& settingsRegistryPath)
{
AZStd::unique_ptr<AZ::SettingsRegistryInterface> settingsRegistry = AZStd::make_unique<AZ::SettingsRegistryImpl>();
if (!settingsRegistry->MergeSettingsFile(settingsRegistryPath, AZ::SettingsRegistryInterface::Format::JsonMergePatch))
{
AZ_Error("AWSCognitoAuthorizationController", true, "Failed to merge settings file for path %s", settingsRegistryPath.c_str());
return false;
}
if (!settingsRegistry->GetObject(m_settings.get(), azrtti_typeid(m_settings.get()), COGNITO_AUTHORIZATION_SETTINGS_PATH))
{
AZ_Error("AWSCognitoAuthorizationController", true, "Failed to get settings object for path %s", COGNITO_AUTHORIZATION_SETTINGS_PATH);
return false;
}
m_persistentCognitoIdentityProvider->Initialize(m_settings->m_awsAccountId.c_str(), m_settings->m_cognitoIdentityPoolId.c_str());
m_persistentAnonymousCognitoIdentityProvider->Initialize(m_settings->m_awsAccountId.c_str(), m_settings->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", true, "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_settings->m_cognitoUserPoolId;
}
case ProviderNameEnum::LoginWithAmazon:
{
return m_settings->m_loginWithAmazonId;
}
case ProviderNameEnum::Google:
{
return m_settings->m_googleId;
}
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", true, "No logins found. Using Anonymous credential provider");
return m_cognitoCachingAnonymousCredentialsProvider;
}
return nullptr;
}
} // namespace AWSClientAuth
@@ -0,0 +1,272 @@
/*
* 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 <AzCore/Jobs/JobFunction.h>
#include <UserManagement/AWSCognitoUserManagementController.h>
#include <AWSClientAuthBus.h>
#include <AWSCoreBus.h>
#include <aws/core/utils/Outcome.h>
#include <aws/core/utils/memory/stl/AWSVector.h>
#include <aws/cognito-idp/model/SignUpRequest.h>
#include <aws/cognito-idp/CognitoIdentityProviderClient.h>
#include <aws/cognito-idp/model/SignUpResult.h>
#include <aws/cognito-idp/model/ConfirmSignUpRequest.h>
#include <aws/cognito-idp/model/ConfirmSignUpResult.h>
#include <aws/cognito-idp/model/ConfirmSignUpRequest.h>
#include <aws/cognito-idp/model/ConfirmSignUpResult.h>
#include <aws/cognito-idp/model/AttributeType.h>
#include <aws/cognito-idp/model/ForgotPasswordRequest.h>
#include <aws/cognito-idp/model/ForgotPasswordResult.h>
#include <aws/cognito-idp/model/ConfirmForgotPasswordRequest.h>
#include <aws/cognito-idp/model/ConfirmForgotPasswordResult.h>
#include <aws/cognito-idp/model/SetUserMFAPreferenceRequest.h>
#include <aws/cognito-idp/model/SetUserMFAPreferenceResult.h>
namespace AWSClientAuth
{
constexpr char COGNITO_USER_POOL[] = "/AWS/CognitoUserPool";
AWSCognitoUserManagementController::AWSCognitoUserManagementController()
{
AZ::Interface<IAWSCognitoUserManagementRequests>::Register(this);
AWSCognitoUserManagementRequestBus::Handler::BusConnect();
m_settings = AZStd::make_unique<AWSCognitoUserManagementSetting>();
}
AWSCognitoUserManagementController::~AWSCognitoUserManagementController()
{
m_settings.reset();
AWSCognitoUserManagementRequestBus::Handler::BusDisconnect();
AZ::Interface<IAWSCognitoUserManagementRequests>::Unregister(this);
}
bool AWSCognitoUserManagementController::Initialize(const AZStd::string& settingsRegistryPath)
{
AZStd::unique_ptr<AZ::SettingsRegistryInterface> settingsRegistry = AZStd::make_unique<AZ::SettingsRegistryImpl>();
if (!settingsRegistry->MergeSettingsFile(settingsRegistryPath, AZ::SettingsRegistryInterface::Format::JsonMergePatch))
{
AZ_Error("AWSCognitoUserManagementController", true, "Failed to merge settings file for path %s", settingsRegistryPath.c_str());
return false;
}
if (!settingsRegistry->GetObject(m_settings.get(), azrtti_typeid(m_settings.get()), COGNITO_USER_POOL))
{
AZ_Error("AWSCognitoUserManagementController", true, "Failed to get settings object for path %s", COGNITO_USER_POOL);
return false;
}
return true;
}
// Call Cognito user pool sign up using email. Confirmation code sent to the email set.
// Refer https://docs.aws.amazon.com/cognito/latest/developerguide/signing-up-users-in-your-app.html
void AWSCognitoUserManagementController::EmailSignUpAsync(const AZStd::string& username, const AZStd::string& password, const AZStd::string& email)
{
std::shared_ptr<Aws::CognitoIdentityProvider::CognitoIdentityProviderClient> cognitoIdentityProviderClient =
AZ::Interface<IAWSClientAuthRequests>::Get()->GetCognitoIDPClient();
AZ::JobContext* jobContext = nullptr;
AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
AZ::Job* emailSignUpJob = AZ::CreateJobFunction([this, cognitoIdentityProviderClient, username, password, email]()
{
Aws::CognitoIdentityProvider::Model::SignUpRequest signUpRequest;
signUpRequest.SetClientId(m_settings->m_appClientId.c_str());
signUpRequest.SetUsername(username.c_str());
signUpRequest.SetPassword(password.c_str());
Aws::Vector<Aws::CognitoIdentityProvider::Model::AttributeType> attributes;
Aws::CognitoIdentityProvider::Model::AttributeType emailAttribute;
emailAttribute.SetName("email");
emailAttribute.SetValue(email.c_str());
attributes.push_back(emailAttribute);
signUpRequest.SetUserAttributes(attributes);
Aws::CognitoIdentityProvider::Model::SignUpOutcome signUpOutcome{ cognitoIdentityProviderClient->SignUp(signUpRequest) };
if (signUpOutcome.IsSuccess())
{
Aws::CognitoIdentityProvider::Model::SignUpResult signUpResult{ signUpOutcome.GetResult() };
AWSCognitoUserManagementNotificationBus::Broadcast(&AWSCognitoUserManagementNotifications::OnEmailSignUpSuccess, signUpResult.GetUserSub().c_str());
}
else
{
Aws::Client::AWSError<Aws::CognitoIdentityProvider::CognitoIdentityProviderErrors> error = signUpOutcome.GetError();
AWSCognitoUserManagementNotificationBus::Broadcast(&AWSCognitoUserManagementNotifications::OnEmailSignUpFail, error.GetMessage().c_str());
}
}, true, jobContext);
emailSignUpJob->Start();
}
void AWSCognitoUserManagementController::PhoneSignUpAsync(const AZStd::string& username, const AZStd::string& password, const AZStd::string& phoneNumber)
{
std::shared_ptr<Aws::CognitoIdentityProvider::CognitoIdentityProviderClient> cognitoIdentityProviderClient =
AZ::Interface<IAWSClientAuthRequests>::Get()->GetCognitoIDPClient();
AZ::JobContext* jobContext = nullptr;
AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
AZ::Job* phoneSignUpJob = AZ::CreateJobFunction([this, cognitoIdentityProviderClient, username, password, phoneNumber]()
{
Aws::CognitoIdentityProvider::Model::SignUpRequest signUpRequest;
signUpRequest.SetClientId(m_settings->m_appClientId.c_str());
signUpRequest.SetUsername(username.c_str());
signUpRequest.SetPassword(password.c_str());
Aws::Vector<Aws::CognitoIdentityProvider::Model::AttributeType> attributes;
Aws::CognitoIdentityProvider::Model::AttributeType emailAttribute;
emailAttribute.SetName("phone_number");
emailAttribute.SetValue(phoneNumber.c_str());
attributes.push_back(emailAttribute);
signUpRequest.SetUserAttributes(attributes);
Aws::CognitoIdentityProvider::Model::SignUpOutcome signUpOutcome{ cognitoIdentityProviderClient->SignUp(signUpRequest) };
if (signUpOutcome.IsSuccess())
{
Aws::CognitoIdentityProvider::Model::SignUpResult signUpResult{ signUpOutcome.GetResult() };
AWSCognitoUserManagementNotificationBus::Broadcast(&AWSCognitoUserManagementNotifications::OnPhoneSignUpSuccess, signUpResult.GetUserSub().c_str());
}
else
{
Aws::Client::AWSError<Aws::CognitoIdentityProvider::CognitoIdentityProviderErrors> error = signUpOutcome.GetError();
AWSCognitoUserManagementNotificationBus::Broadcast(&AWSCognitoUserManagementNotifications::OnPhoneSignUpFail, error.GetMessage().c_str());
}
}, true, jobContext);
phoneSignUpJob->Start();
}
// Call Cognito user pool confirm sign up using code from email/phone.
// Refer https://docs.aws.amazon.com/cognito/latest/developerguide/signing-up-users-in-your-app.html
void AWSCognitoUserManagementController::ConfirmSignUpAsync(const AZStd::string& username, const AZStd::string& confirmationCode)
{
std::shared_ptr<Aws::CognitoIdentityProvider::CognitoIdentityProviderClient> cognitoIdentityProviderClient =
AZ::Interface<IAWSClientAuthRequests>::Get()->GetCognitoIDPClient();
AZ::JobContext* jobContext = nullptr;
AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
AZ::Job* confirmSignUpJob = AZ::CreateJobFunction([this, cognitoIdentityProviderClient, username, confirmationCode]()
{
Aws::CognitoIdentityProvider::Model::ConfirmSignUpRequest confirmSignupRequest;
confirmSignupRequest.SetClientId(m_settings->m_appClientId.c_str());
confirmSignupRequest.SetUsername(username.c_str());
confirmSignupRequest.SetConfirmationCode(confirmationCode.c_str());
Aws::CognitoIdentityProvider::Model::ConfirmSignUpOutcome confirmSignupOutcome{ cognitoIdentityProviderClient->ConfirmSignUp(confirmSignupRequest) };
if (confirmSignupOutcome.IsSuccess())
{
AWSCognitoUserManagementNotificationBus::Broadcast(&AWSCognitoUserManagementNotifications::OnConfirmSignUpSuccess);
}
else
{
Aws::Client::AWSError<Aws::CognitoIdentityProvider::CognitoIdentityProviderErrors> error = confirmSignupOutcome.GetError();
AWSCognitoUserManagementNotificationBus::Broadcast(&AWSCognitoUserManagementNotifications::OnConfirmSignUpFail, error.GetMessage().c_str());
}
}, true, jobContext);
confirmSignUpJob->Start();
}
void AWSCognitoUserManagementController::ForgotPasswordAsync(const AZStd::string& username)
{
std::shared_ptr<Aws::CognitoIdentityProvider::CognitoIdentityProviderClient> cognitoIdentityProviderClient =
AZ::Interface<IAWSClientAuthRequests>::Get()->GetCognitoIDPClient();
AZ::JobContext* jobContext = nullptr;
AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
AZ::Job* forgotPasswordJob = AZ::CreateJobFunction([this, cognitoIdentityProviderClient, username]()
{
Aws::CognitoIdentityProvider::Model::ForgotPasswordRequest forgotPasswordRequest;
forgotPasswordRequest.SetClientId(m_settings->m_appClientId.c_str());
forgotPasswordRequest.SetUsername(username.c_str());
Aws::CognitoIdentityProvider::Model::ForgotPasswordOutcome forgotPasswordOutcome{ cognitoIdentityProviderClient->ForgotPassword(forgotPasswordRequest) };
if (forgotPasswordOutcome.IsSuccess())
{
AWSCognitoUserManagementNotificationBus::Broadcast(&AWSCognitoUserManagementNotifications::OnForgotPasswordSuccess);
}
else
{
Aws::Client::AWSError<Aws::CognitoIdentityProvider::CognitoIdentityProviderErrors> error = forgotPasswordOutcome.GetError();
AWSCognitoUserManagementNotificationBus::Broadcast(&AWSCognitoUserManagementNotifications::OnForgotPasswordFail, error.GetMessage().c_str());
}
}, true, jobContext);
forgotPasswordJob->Start();
}
void AWSCognitoUserManagementController::ConfirmForgotPasswordAsync(const AZStd::string& username, const AZStd::string& confirmationCode, const AZStd::string& newPassword)
{
std::shared_ptr<Aws::CognitoIdentityProvider::CognitoIdentityProviderClient> cognitoIdentityProviderClient =
AZ::Interface<IAWSClientAuthRequests>::Get()->GetCognitoIDPClient();
AZ::JobContext* jobContext = nullptr;
AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
AZ::Job* confirmForgotPasswordJob = AZ::CreateJobFunction([this, cognitoIdentityProviderClient, username, confirmationCode, newPassword]()
{
Aws::CognitoIdentityProvider::Model::ConfirmForgotPasswordRequest confirmForgotPasswordRequest;
confirmForgotPasswordRequest.SetClientId(m_settings->m_appClientId.c_str());
confirmForgotPasswordRequest.SetUsername(username.c_str());
confirmForgotPasswordRequest.SetConfirmationCode(confirmationCode.c_str());
confirmForgotPasswordRequest.SetPassword(newPassword.c_str());
Aws::CognitoIdentityProvider::Model::ConfirmForgotPasswordOutcome confirmForgotPasswordOutcome{ cognitoIdentityProviderClient->ConfirmForgotPassword(confirmForgotPasswordRequest) };
if (confirmForgotPasswordOutcome.IsSuccess())
{
AWSCognitoUserManagementNotificationBus::Broadcast(&AWSCognitoUserManagementNotifications::OnConfirmForgotPasswordSuccess);
}
else
{
Aws::Client::AWSError<Aws::CognitoIdentityProvider::CognitoIdentityProviderErrors> error = confirmForgotPasswordOutcome.GetError();
AWSCognitoUserManagementNotificationBus::Broadcast(&AWSCognitoUserManagementNotifications::OnConfirmForgotPasswordFail, error.GetMessage().c_str());
}
}, true, jobContext);
confirmForgotPasswordJob->Start();
}
void AWSCognitoUserManagementController::EnableMFAAsync(const AZStd::string& accessToken)
{
std::shared_ptr<Aws::CognitoIdentityProvider::CognitoIdentityProviderClient> cognitoIdentityProviderClient =
AZ::Interface<IAWSClientAuthRequests>::Get()->GetCognitoIDPClient();
AZ::JobContext* jobContext = nullptr;
AWSCore::AWSCoreRequestBus::BroadcastResult(jobContext, &AWSCore::AWSCoreRequests::GetDefaultJobContext);
AZ::Job* enableMFAJob = AZ::CreateJobFunction([this, cognitoIdentityProviderClient, accessToken]()
{
Aws::CognitoIdentityProvider::Model::SetUserMFAPreferenceRequest confirmForgotPasswordRequest;
Aws::CognitoIdentityProvider::Model::SMSMfaSettingsType settings;
settings.SetEnabled(true);
settings.SetPreferredMfa(true);
confirmForgotPasswordRequest.SetSMSMfaSettings(settings);
confirmForgotPasswordRequest.SetAccessToken(accessToken.c_str());
Aws::CognitoIdentityProvider::Model::SetUserMFAPreferenceOutcome setUserMFAPreferenceOutcome{ cognitoIdentityProviderClient->SetUserMFAPreference(confirmForgotPasswordRequest) };
if (setUserMFAPreferenceOutcome.IsSuccess())
{
AWSCognitoUserManagementNotificationBus::Broadcast(&AWSCognitoUserManagementNotifications::OnEnableMFASuccess);
}
else
{
Aws::Client::AWSError<Aws::CognitoIdentityProvider::CognitoIdentityProviderErrors> error = setUserMFAPreferenceOutcome.GetError();
AWSCognitoUserManagementNotificationBus::Broadcast(&AWSCognitoUserManagementNotifications::OnEnableMFAFail, error.GetMessage().c_str());
}
}, true, jobContext);
enableMFAJob->Start();
}
} // namespace AWSClientAuth