@@ -63,10 +63,17 @@ const DefaultActiveDirectoryEndpoint = "https://login.microsoftonline.com"
6363
6464const TokenCache = "AzCopyTokenCache"
6565
66+ type CredCacheImplementation interface {
67+ HasCachedToken () (bool , error )
68+ LoadToken () (* OAuthTokenInfo , error )
69+ SaveToken (OAuthTokenInfo ) error
70+ RemoveCachedToken () error
71+ }
72+
6673// UserOAuthTokenManager for token management.
6774type UserOAuthTokenManager struct {
6875 oauthClient * http.Client
69- credCache * CredCache
76+ credCache CredCacheImplementation
7077
7178 // Stash the credential info as we delete the environment variable after reading it, and we need to get it multiple times.
7279 stashedInfo * OAuthTokenInfo
@@ -479,7 +486,7 @@ func (credInfo *OAuthTokenInfo) Refresh(ctx context.Context) (*Token, error) {
479486}
480487
481488// Single instance token store credential cache shared by entire azcopy process.
482- var tokenStoreCredCache = NewCredCacheInternalIntegration (CredCacheOptions {
489+ var tokenStoreCredCache CredCacheImplementation = NewCredCacheInternalIntegration (CredCacheOptions {
483490 KeyName : "azcopy/aadtoken/" + strconv .Itoa (os .Getpid ()),
484491 ServiceName : "azcopy" ,
485492 AccountName : "aadtoken/" + strconv .Itoa (os .Getpid ()),
@@ -510,8 +517,9 @@ func getAuthorityURL(activeDirectoryEndpoint string) (*url.URL, error) {
510517const minimumTokenValidDuration = time .Minute * 5
511518
512519type TokenStoreCredential struct {
513- token * azcore.AccessToken
514- lock sync.RWMutex
520+ token * azcore.AccessToken
521+ lock sync.RWMutex
522+ credCache CredCacheImplementation
515523}
516524
517525// globalTokenStoreCredential is created to make sure that all
@@ -531,22 +539,26 @@ var globalTokenStoreCredential *TokenStoreCredential
531539var globalTsc sync.Once
532540
533541func (tsc * TokenStoreCredential ) GetToken (_ context.Context , _ policy.TokenRequestOptions ) (azcore.AccessToken , error ) {
534- // if the token we've has not expired, return the same.
542+ // if the token we have has not expired, return the same.
535543 tsc .lock .RLock ()
536- if time .Until (tsc .token .ExpiresOn ) > minimumTokenValidDuration {
544+ if rem := time .Until (tsc .token .ExpiresOn ); rem > minimumTokenValidDuration {
545+ tsc .lock .RUnlock () // return path, so we must release the read lock here as well.
537546 return * tsc .token , nil
538547 }
539548 tsc .lock .RUnlock ()
540549
541550 tsc .lock .Lock ()
542551 defer tsc .lock .Unlock ()
543- hasToken , err := tokenStoreCredCache .HasCachedToken ()
552+
553+ hasToken , err := tsc .credCache .HasCachedToken ()
544554 if err != nil || ! hasToken {
555+ AzcopyCurrentJobLogger .Log (LogDebug , fmt .Sprintf ("no token found %v" , err ))
545556 return azcore.AccessToken {}, fmt .Errorf ("no cached token found in Token Store Mode(SE), %w" , err )
546557 }
547558
548- tokenInfo , err := tokenStoreCredCache .LoadToken ()
559+ tokenInfo , err := tsc . credCache .LoadToken ()
549560 if err != nil {
561+ AzcopyCurrentJobLogger .Log (LogDebug , fmt .Sprintf ("get token failed %s" , err .Error ()))
550562 return azcore.AccessToken {}, fmt .Errorf ("get cached token failed in Token Store Mode(SE), %w" , err )
551563 }
552564
@@ -568,6 +580,7 @@ func GetTokenStoreCredential(accessToken string, expiresOn time.Time) azcore.Tok
568580 Token : accessToken ,
569581 ExpiresOn : expiresOn ,
570582 },
583+ credCache : tokenStoreCredCache ,
571584 }
572585 })
573586 return globalTokenStoreCredential
0 commit comments