BearerTokenAuthenticationPolicy to use shared_lock in case no refresh is needed (#5188)

* `BearerTokenAuthenticationPolicy` to use shared_lock in case no refresh is needed

* Copy constructor

* Update bearer_token_authentication_policy.cpp

---------

Co-authored-by: Anton Kolesnyk <antkmsft@users.noreply.github.com>
This commit is contained in:
Anton Kolesnyk 2023-11-28 13:29:54 -08:00 committed by GitHub
parent b997e76e0d
commit 135e746243
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 7 deletions

View File

@ -13,6 +13,8 @@
### Other Changes
- [[#4756]] (https://github.com/Azure/azure-sdk-for-cpp/issues/4756) `BearerTokenAuthenticationPolicy` now uses shared mutex lock for read operations.
## 1.11.0-beta.2 (2023-11-02)
### Features Added

View File

@ -25,6 +25,7 @@
#include <memory>
#include <mutex>
#include <set>
#include <shared_mutex>
#include <string>
#include <utility>
#include <vector>
@ -549,7 +550,7 @@ namespace Azure { namespace Core { namespace Http { namespace Policies {
Credentials::TokenRequestContext m_tokenRequestContext;
mutable Credentials::AccessToken m_accessToken;
mutable std::mutex m_accessTokenMutex;
mutable std::shared_timed_mutex m_accessTokenMutex;
mutable Credentials::TokenRequestContext m_accessTokenContext;
public:
@ -581,6 +582,9 @@ namespace Azure { namespace Core { namespace Http { namespace Policies {
BearerTokenAuthenticationPolicy(BearerTokenAuthenticationPolicy const& other)
: BearerTokenAuthenticationPolicy(other.m_credential, other.m_tokenRequestContext)
{
std::shared_lock<std::shared_timed_mutex> readLock(other.m_accessTokenMutex);
m_accessToken = other.m_accessToken;
m_accessTokenContext = other.m_accessTokenContext;
}
void operator=(BearerTokenAuthenticationPolicy const&) = delete;

View File

@ -61,21 +61,49 @@ bool BearerTokenAuthenticationPolicy::AuthorizeRequestOnChallenge(
return false;
}
namespace {
bool TokenNeedsRefresh(
Azure::Core::Credentials::AccessToken const& cachedToken,
Azure::Core::Credentials::TokenRequestContext const& cachedTokenRequestContext,
Azure::DateTime const& currentTime,
Azure::Core::Credentials::TokenRequestContext const& newTokenRequestContext)
{
return newTokenRequestContext.TenantId != cachedTokenRequestContext.TenantId
|| newTokenRequestContext.Scopes != cachedTokenRequestContext.Scopes
|| currentTime > (cachedToken.ExpiresOn - newTokenRequestContext.MinimumExpiration);
}
void ApplyBearerToken(
Azure::Core::Http::Request& request,
Azure::Core::Credentials::AccessToken const& token)
{
request.SetHeader("authorization", "Bearer " + token.Token);
}
} // namespace
void BearerTokenAuthenticationPolicy::AuthenticateAndAuthorizeRequest(
Request& request,
Credentials::TokenRequestContext const& tokenRequestContext,
Context const& context) const
{
std::lock_guard<std::mutex> lock(m_accessTokenMutex);
DateTime const currentTime = std::chrono::system_clock::now();
if (tokenRequestContext.TenantId != m_accessTokenContext.TenantId
|| tokenRequestContext.Scopes != m_accessTokenContext.Scopes
|| std::chrono::system_clock::now()
> (m_accessToken.ExpiresOn - tokenRequestContext.MinimumExpiration))
{
std::shared_lock<std::shared_timed_mutex> readLock(m_accessTokenMutex);
if (!TokenNeedsRefresh(m_accessToken, m_accessTokenContext, currentTime, tokenRequestContext))
{
ApplyBearerToken(request, m_accessToken);
return;
}
}
std::unique_lock<std::shared_timed_mutex> writeLock(m_accessTokenMutex);
// Check if token needs refresh for the second time in case another thread has just updated it.
if (TokenNeedsRefresh(m_accessToken, m_accessTokenContext, currentTime, tokenRequestContext))
{
m_accessToken = m_credential->GetToken(tokenRequestContext, context);
m_accessTokenContext = tokenRequestContext;
}
request.SetHeader("authorization", "Bearer " + m_accessToken.Token);
ApplyBearerToken(request, m_accessToken);
}