< Summary

Class:Microsoft.Azure.ContainerRegistry.AuthToken
Assembly:Microsoft.Azure.ContainerRegistry
File(s):C:\Git\azure-sdk-for-net\sdk\containerregistry\Microsoft.Azure.ContainerRegistry\src\Customizations\AuthToken.cs
Covered lines:0
Uncovered lines:25
Coverable lines:25
Total lines:191
Line coverage:0% (0 of 25)
Covered branches:0
Total branches:4
Branch coverage:0% (0 of 4)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.cctor()-0%100%
.ctor(...)-0%100%
get_Value()-0%100%
get_Expiration()-0%100%
.ctor(...)-0%100%
.ctor()-0%100%
Refresh()-0%0%
NeedsRefresh()-0%100%
CheckAndRefresh()-0%0%
InitializeToken(...)-0%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\containerregistry\Microsoft.Azure.ContainerRegistry\src\Customizations\AuthToken.cs

#LineLine coverage
 1using Microsoft.Rest;
 2using System;
 3using System.IdentityModel.Tokens.Jwt;
 4using System.Net.Http;
 5using System.Net.Http.Headers;
 6using System.Threading;
 7using System.Threading.Tasks;
 8
 9namespace Microsoft.Azure.ContainerRegistry
 10{
 11    /// <summary>
 12    /// Simple authentication credentials class for use by local clients within Token classes.
 13    /// i.e <see cref="ContainerRegistryRefreshToken"/> and <see cref="ContainerRegistryAccessToken">
 14    /// </summary>
 15    internal class TokenCredentials : ServiceClientCredentials
 16    {
 17        private string _authHeader { get; set; }
 18
 19        /*To be used for General Login Scheme*/
 20        public TokenCredentials(string username, string password)
 21        {
 22            _authHeader = Helpers.EncodeTo64($"{username}:{password}");
 23        }
 24
 25        /*To be used for exchanging AAD Tokens for ACR Tokens*/
 26        public TokenCredentials()
 27        {
 28            _authHeader = null;
 29        }
 30
 31        public override async Task ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationTok
 32        {
 33            if (request == null)
 34            {
 35                throw new ArgumentNullException(nameof(request));
 36            }
 37            if (_authHeader != null)
 38            {
 39                request.Headers.Authorization = new AuthenticationHeaderValue("Basic", _authHeader);
 40            }
 41            await base.ProcessHttpRequestAsync(request, cancellationToken);
 42        }
 43    }
 44
 45    /// <summary>
 46    /// AuthToken class for chaining token refreshes. It abstracts checking and refresh logic and allows for chained tok
 47    /// See subclasses <see cref="ContainerRegistryRefreshToken"/> and <see cref="ContainerRegistryAccessToken"> for mor
 48    /// </summary>
 49    public class AuthToken
 50    {
 51        public delegate string AcquireCallback();
 052        protected static readonly JwtSecurityTokenHandler JwtSecurityClient = new JwtSecurityTokenHandler();
 53
 54        // Constant to refresh tokens slightly before they are to expire guarding against possible latency related crash
 055        private readonly TimeSpan LatencySafety = TimeSpan.FromMinutes(2);
 56
 057        public string Value { get; set; }
 058        public DateTime Expiration { get; set; }
 59        protected AcquireCallback RefreshFunction;
 60
 061        public AuthToken(string token)
 62        {
 063            Value = token;
 064            Expiration = JwtSecurityClient.ReadToken(Value).ValidTo;
 065        }
 66
 067        public AuthToken(string token, AcquireCallback refreshFunction) : this(token)
 68        {
 069            RefreshFunction = refreshFunction;
 070        }
 71
 72        //Extensibility purposes
 073        protected AuthToken() { }
 74
 75
 76        /* Returns true if refresh was successful. */
 77        public bool Refresh()
 78        {
 079            if (RefreshFunction == null)
 80            {
 081                return false;
 82            }
 083            Value = RefreshFunction();
 084            Expiration = JwtSecurityClient.ReadToken(Value).ValidTo;
 85
 086            return true;
 87        }
 88
 89        public bool NeedsRefresh()
 90        {
 091            return Expiration < DateTime.UtcNow.Add(LatencySafety);
 92        }
 93
 94        // Returns true if token is ready for use or false if token was expired and unable to refresh
 95        public bool CheckAndRefresh()
 96        {
 097            if (NeedsRefresh())
 098                return Refresh();
 099            return true;
 100        }
 101
 102        protected void InitializeToken(AcquireCallback refreshFunction)
 103        {
 0104            Value = refreshFunction();
 0105            Expiration = JwtSecurityClient.ReadToken(Value).ValidTo;
 0106            RefreshFunction = refreshFunction;
 0107        }
 108    }
 109
 110    /// <summary>
 111    /// An ACR refresh token that refreshes from an AAD access token. Provides built in token exchange functionality.
 112    /// </summary>
 113    public class ContainerRegistryRefreshToken : AuthToken
 114    {
 115        private AzureContainerRegistryClient authClient;
 116        public ContainerRegistryRefreshToken(AuthToken aadToken, string loginUrl)
 117        {
 118            // setup refresh function to retrieve acrtoken with aadtoken
 119            authClient = new AzureContainerRegistryClient(new TokenCredentials())
 120            {
 121                LoginUri = $"https://{loginUrl}"
 122            };
 123
 124            string tempRefreshFunction()
 125            {
 126                // Note: should be using real new access token
 127                aadToken.CheckAndRefresh();
 128                return authClient.RefreshTokens.GetFromExchangeAsync("access_token", loginUrl, "", null, aadToken.Value)
 129            }
 130
 131            // initialize token and refresh function
 132            InitializeToken(tempRefreshFunction);
 133        }
 134    }
 135
 136    /// <summary>
 137    /// An ACR access token that refreshes from an ACR refresh token or username and password.
 138    /// </summary>
 139    public class ContainerRegistryAccessToken : AuthToken
 140    {
 141        private AzureContainerRegistryClient authClient;
 142        public string Scope { get; set; }
 143        /// <summary>
 144        /// Construct an ACR access token that refreshes from an ACR refresh token.
 145        /// </summary>
 146        /// <param name="acrRefresh"></param>
 147        /// <param name="scope"></param>
 148        /// <param name="loginUrl"></param>
 149        public ContainerRegistryAccessToken(ContainerRegistryRefreshToken refreshToken, string scope, string loginUrl)
 150        {
 151            Scope = scope;
 152            authClient = new AzureContainerRegistryClient(new TokenCredentials())
 153            {
 154                LoginUri = $"https://{loginUrl}"
 155            };
 156            string tempRefreshFunction()
 157            {
 158                refreshToken.CheckAndRefresh();
 159                return authClient.AccessTokens.GetAsync(loginUrl, scope, refreshToken.Value).GetAwaiter().GetResult().Ac
 160            };
 161
 162            // initialize token and refresh function
 163            InitializeToken(tempRefreshFunction);
 164        }
 165
 166        /// <summary>
 167        /// Construct an ACR access token that refreshes from an ACR refresh token.
 168        /// </summary>
 169        /// <param name="username"></param>
 170        /// <param name="password"></param>
 171        /// <param name="scope"></param>
 172        /// <param name="loginUrl"></param>
 173        public ContainerRegistryAccessToken(string username, string password, string scope, string loginUrl)
 174        {
 175            Scope = scope;
 176            authClient = new AzureContainerRegistryClient(new TokenCredentials(username, password))
 177            {
 178                LoginUri = $"https://{loginUrl}"
 179            };
 180            string tempRefreshFunction()
 181            {
 182                return authClient.AccessTokens.GetFromLoginAsync(loginUrl, scope).GetAwaiter().GetResult().AccessTokenPr
 183            };
 184
 185            // initialize token and refresh function
 186            InitializeToken(tempRefreshFunction);
 187        }
 188    }
 189}
 190
 191