public void ContainerRegistryChallengeAuthenticationPolicy_OneHundredConcurrentCallsFailed()
        {
            MockAuthenticationClient mockAuthClient = new MockAuthenticationClient(
                service =>
            {
                Thread.Sleep(100);
                throw new InvalidOperationException("Error");
            },
                (service, scope) =>
            {
                return(new AcrAccessToken("TestAcrAccessToken"));
            });

            var           policy       = new ContainerRegistryChallengeAuthenticationPolicy(new MockCredential(), "scope", mockAuthClient);
            MockTransport transport    = CreateMockTransport(r => GetChallengeResponse());
            var           requestTasks = new Task <Response> [100];

            for (int i = 0; i < requestTasks.Length; i++)
            {
                requestTasks[i] = SendGetRequest(transport, policy, uri: new Uri("https://example.com"));
            }

            Assert.CatchAsync(async() => await Task.WhenAll(requestTasks));

            foreach (Task <Response> task in requestTasks)
            {
                Assert.IsTrue(task.IsFaulted);
            }
        }
        public async Task ContainerRegistryChallengeAuthenticationPolicy_OneHundredConcurrentCalls()
        {
            MockAuthenticationClient mockAuthClient = new MockAuthenticationClient(
                service => new AcrRefreshToken("TestAcrRefreshToken"),
                (service, scope) =>
            {
                Thread.Sleep(100);
                return(new AcrAccessToken("TestAcrAccessToken"));
            });

            var           policy       = new ContainerRegistryChallengeAuthenticationPolicy(new MockCredential(), "scope", mockAuthClient);
            MockTransport transport    = CreateMockTransport(r => GetChallengeResponse());
            var           requestTasks = new Task <Response> [100];

            for (int i = 0; i < requestTasks.Length; i++)
            {
                requestTasks[i] = SendGetRequest(transport, policy, uri: new Uri("https://example.com"));
            }

            await Task.WhenAll(requestTasks);

            Assert.True(transport.Requests[0].Headers.TryGetValue("Authorization", out string auth1Value));

            for (int i = 1; i < requestTasks.Length; i++)
            {
                Assert.True(transport.Requests[i].Headers.TryGetValue("Authorization", out string authValue));
                Assert.AreEqual(auth1Value, authValue);
            }
        }
        public void ContainerRegistryChallengeAuthenticationPolicy_ThrowsForNonTlsEndpoint()
        {
            MockAuthenticationClient mockAuthClient = GetMockAuthClient();
            var           policy    = new ContainerRegistryChallengeAuthenticationPolicy(new MockCredential(), "scope", mockAuthClient);
            MockTransport transport = CreateMockTransport();

            Assert.ThrowsAsync <InvalidOperationException>(async() => await SendGetRequest(transport, policy, uri: new Uri("http://example.com")));
        }
        public async Task ContainerRegistryChallengeAuthenticationPolicy_CachesRefreshToken()
        {
            // Arrange
            int refreshTokenRequests = 0;
            int accessTokenRequests  = 0;

            string mockJwt = GetMockJwt(TimeSpan.FromHours(3));

            // We expect the refresh token request method to be called only the first time.
            MockAuthenticationClient mockClient = new MockAuthenticationClient(
                service =>
            {
                refreshTokenRequests++;
                return(new AcrRefreshToken(mockJwt));
            },
                (service, scope) =>
            {
                accessTokenRequests++;
                return(new AcrAccessToken($"TestAcrAccessToken{accessTokenRequests}"));
            });
            MockCredential mockCredential = new MockCredential();

            var policy = new ContainerRegistryChallengeAuthenticationPolicy(mockCredential, "TestScope", mockClient);

            // We'll send two GET requests - each will receive a challenge response
            MockTransport transport = CreateMockTransport(
                GetChallengeResponse(), new MockResponse(200),
                GetChallengeResponse(), new MockResponse(200));

            // Act
            await SendGetRequest(transport, policy, uri : new Uri("https://example.azurecr.io/acr/v1/hello-world/_tags/latest"), cancellationToken : default);

            MockRequest firstRequest = transport.Requests[0];

            // Assert
            string authHeaderValue;

            Assert.IsTrue(firstRequest.Headers.TryGetValue(HttpHeader.Names.Authorization, out authHeaderValue));
            Assert.AreEqual("Bearer TestAcrAccessToken1", authHeaderValue);
            Assert.AreEqual(1, refreshTokenRequests);
            Assert.AreEqual(1, accessTokenRequests);

            // Act
            await SendGetRequest(transport, policy, uri : new Uri("https://example.azurecr.io/acr/v1/hello-world/_tags/latest"), cancellationToken : default);

            MockRequest secondRequest = transport.Requests[2];

            // Assert
            Assert.IsTrue(secondRequest.Headers.TryGetValue(HttpHeader.Names.Authorization, out authHeaderValue));
            Assert.AreEqual("Bearer TestAcrAccessToken2", authHeaderValue);
            Assert.AreEqual(1, refreshTokenRequests);
            Assert.AreEqual(2, accessTokenRequests);
        }
        public async Task ContainerRegistryChallengeAuthenticationPolicy_RequestsTokenOnForceRefresh()
        {
            // Arrange
            int refreshTokenRequests = 0;
            int accessTokenRequests  = 0;

            MockAuthenticationClient mockClient = new MockAuthenticationClient(
                service =>
            {
                refreshTokenRequests++;
                return(new AcrRefreshToken(GetMockJwt(TimeSpan.FromHours(3))));
            },
                (service, scope) =>
            {
                accessTokenRequests++;
                return(new AcrAccessToken($"TestAcrAccessToken{accessTokenRequests}"));
            });
            MockCredential mockCredential = new MockCredential();

            var policy = new ContainerRegistryChallengeAuthenticationPolicy(mockCredential, "TestScope", mockClient);

            // Getting a different service name will invalidate the token and force a refresh.
            MockTransport transport = CreateMockTransport(
                GetChallengeResponse("example1"), new MockResponse(200),
                GetChallengeResponse("example2"), new MockResponse(200));

            // Act
            await SendGetRequest(transport, policy, uri : new Uri("https://example.azurecr.io/acr/v1/hello-world/_tags/latest"), cancellationToken : default);

            MockRequest firstRequest = transport.Requests[0];

            // Assert
            string authHeaderValue;

            Assert.IsTrue(firstRequest.Headers.TryGetValue(HttpHeader.Names.Authorization, out authHeaderValue));
            Assert.AreEqual("Bearer TestAcrAccessToken1", authHeaderValue);
            Assert.AreEqual(1, refreshTokenRequests);
            Assert.AreEqual(1, accessTokenRequests);

            // Act
            await SendGetRequest(transport, policy, uri : new Uri("https://example.azurecr.io/acr/v1/hello-world/_tags/latest"), cancellationToken : default);

            MockRequest secondRequest = transport.Requests[2];

            // Assert
            Assert.IsTrue(secondRequest.Headers.TryGetValue(HttpHeader.Names.Authorization, out authHeaderValue));
            Assert.AreEqual("Bearer TestAcrAccessToken2", authHeaderValue);
            Assert.AreEqual(2, refreshTokenRequests);
            Assert.AreEqual(2, accessTokenRequests);
        }
        public async Task ContainerRegistryChallengeAuthenticationPolicy_UsesTokenProvidedByAuthClient()
        {
            MockAuthenticationClient mockClient     = GetMockAuthClient();
            MockCredential           mockCredential = new MockCredential();

            var policy = new ContainerRegistryChallengeAuthenticationPolicy(mockCredential, "TestScope", mockClient);

            MockTransport transport = CreateMockTransport(GetChallengeResponse(), new MockResponse(200));

            await SendGetRequest(transport, policy, uri : new Uri("https://example.azurecr.io/acr/v1/hello-world/_tags/latest"), cancellationToken : default);

            MockRequest request = transport.Requests[0];

            Assert.IsTrue(request.Headers.TryGetValue(HttpHeader.Names.Authorization, out string authHeaderValue));
            Assert.AreEqual("Bearer TestAcrAccessToken", authHeaderValue);
        }
        public async Task ChallengePolicySetsToken()
        {
            MockAuthenticationClient mockClient     = new MockAuthenticationClient();
            MockCredential           mockCredential = new MockCredential();

            var policy = new ContainerRegistryChallengeAuthenticationPolicy(mockCredential, "TestScope", mockClient);

            var    challengeResponse = new MockResponse(401);
            string challenge         = "Bearer realm=\"https://example.azurecr.io/oauth2/token\",service=\"example.azurecr.io\",scope=\"repository:library/hello-world:metadata_read\",error=\"invalid_token\"";

            challengeResponse.AddHeader(new HttpHeader(HttpHeader.Names.WwwAuthenticate, challenge));

            MockTransport transport = CreateMockTransport(challengeResponse, new MockResponse(200));

            await SendGetRequest(transport, policy, uri : new Uri("https://example.azurecr.io/acr/v1/hello-world/_tags/latest"), cancellationToken : default);

            MockRequest request = transport.Requests[0];

            Assert.IsTrue(request.Headers.TryGetValue(HttpHeader.Names.Authorization, out string authHeaderValue));
            Assert.AreEqual("Bearer TestAcrAccessToken", authHeaderValue);
        }
        public async Task ContainerRegistryChallengeAuthenticationPolicy_RefreshesRefreshToken()
        {
            // Arrange
            int      refreshTokenRequests = 0;
            int      accessTokenRequests  = 0;
            TimeSpan refreshOffset        = TimeSpan.FromSeconds(30);
            TimeSpan expiryTime           = TimeSpan.FromSeconds(35);

            string mockJwt = GetMockJwt(expiryTime);

            // We expect the refresh token request method to be called the first and third times.
            MockAuthenticationClient mockClient = new MockAuthenticationClient(
                service =>
            {
                refreshTokenRequests++;
                return(new AcrRefreshToken(mockJwt));
            },
                (service, scope) =>
            {
                accessTokenRequests++;
                return(new AcrAccessToken($"TestAcrAccessToken{accessTokenRequests}"));
            });
            MockCredential mockCredential = new MockCredential();

            // Set expiration 5 seconds longer than refresh time.  Result should be that it tries to refresh in 5 seconds.
            var policy = new ContainerRegistryChallengeAuthenticationPolicy(mockCredential, "TestScope", mockClient, tokenRefreshOffset: refreshOffset);

            // We'll send three GET requests - each will receive a challenge response
            // In the last one, the token will need to be refreshed so a new request for it will be sent
            MockTransport transport = CreateMockTransport(
                GetChallengeResponse(), new MockResponse(200),
                GetChallengeResponse(), new MockResponse(200),
                GetChallengeResponse(), new MockResponse(200));

            // Act
            await SendGetRequest(transport, policy, uri : new Uri("https://example.azurecr.io/acr/v1/hello-world/_tags/latest"), cancellationToken : default);

            MockRequest firstRequest = transport.Requests[0];

            // Assert
            string authHeaderValue;

            Assert.IsTrue(firstRequest.Headers.TryGetValue(HttpHeader.Names.Authorization, out authHeaderValue));
            Assert.AreEqual("Bearer TestAcrAccessToken1", authHeaderValue);
            Assert.AreEqual(1, refreshTokenRequests);
            Assert.AreEqual(1, accessTokenRequests);

            // Act
            await SendGetRequest(transport, policy, uri : new Uri("https://example.azurecr.io/acr/v1/hello-world/_tags/latest"), cancellationToken : default);

            MockRequest secondRequest = transport.Requests[2];

            // Assert
            Assert.IsTrue(secondRequest.Headers.TryGetValue(HttpHeader.Names.Authorization, out authHeaderValue));
            Assert.AreEqual("Bearer TestAcrAccessToken2", authHeaderValue);
            Assert.AreEqual(1, refreshTokenRequests);
            Assert.AreEqual(2, accessTokenRequests);

            // Act
            await Task.Delay(expiryTime - refreshOffset);

            await SendGetRequest(transport, policy, uri : new Uri("https://example.azurecr.io/acr/v1/hello-world/_tags/latest"), cancellationToken : default);

            MockRequest thirdRequest = transport.Requests[4];

            // Wait for bg thread to complete its refresh request.
            await Task.Delay(TimeSpan.FromSeconds(1));

            // Assert
            Assert.IsTrue(thirdRequest.Headers.TryGetValue(HttpHeader.Names.Authorization, out authHeaderValue));
            Assert.AreEqual("Bearer TestAcrAccessToken3", authHeaderValue);
            Assert.AreEqual(2, refreshTokenRequests);
            Assert.AreEqual(3, accessTokenRequests);
        }