public void CallbackUri_ForcesStrategy(LocalServerCodeReceiver.CallbackUriChooserStrategy strategy, string expectedTemplate)
        {
            MockClock clock   = new MockClock(DateTime.UtcNow);
            TimeSpan  timeout = TimeSpan.FromMinutes(1);
            // Make the template that should be forced, fail on the listener check.
            Func <string, bool> listenerFails = u => u == expectedTemplate;

            var chooser = new LocalServerCodeReceiver.CallbackUriChooser(clock, timeout, listenerFails);

            var uri1 = chooser.GetUriTemplate(strategy);

            // Even after time out
            clock.UtcNow = clock.UtcNow.AddMinutes(2);

            var uri2 = chooser.GetUriTemplate(strategy);

            // Even if a failure is reported, it succeeded at least once
            // so the failure is transient.
            chooser.ReportFailure(expectedTemplate);

            var uri3 = chooser.GetUriTemplate(strategy);

            Assert.Equal(expectedTemplate, uri1);
            Assert.Equal(expectedTemplate, uri2);
            Assert.Equal(expectedTemplate, uri3);
        }
        public async Task GetPublicKeysWithCaching()
        {
            var clock        = new MockClock();
            var cacheControl = new CacheControlHeaderValue()
            {
                MaxAge = new TimeSpan(hours: 1, minutes: 0, seconds: 0),
            };
            var handler = new MockMessageHandler()
            {
                Response     = File.ReadAllBytes("./resources/public_keys.json"),
                ApplyHeaders = (header, _) => header.CacheControl = cacheControl,
            };
            var clientFactory = new MockHttpClientFactory(handler);
            var keyManager    = new HttpPublicKeySource(
                "https://example.com/certs", clock, clientFactory);
            var keys = await keyManager.GetPublicKeysAsync();

            Assert.Equal(2, keys.Count);
            Assert.Equal(1, handler.Calls);

            clock.UtcNow = clock.UtcNow.AddMinutes(50);
            var keys2 = await keyManager.GetPublicKeysAsync();

            Assert.Equal(2, keys.Count);
            Assert.Equal(1, handler.Calls);
            Assert.Same(keys, keys2);

            clock.UtcNow = clock.UtcNow.AddMinutes(10);
            var keys3 = await keyManager.GetPublicKeysAsync();

            Assert.Equal(2, keys.Count);
            Assert.Equal(2, handler.Calls);
            Assert.NotSame(keys, keys3);
        }
        public void CallbackUri_TimeoutPreferredForRetries()
        {
            MockClock           clock         = new MockClock(DateTime.UtcNow);
            TimeSpan            timeout       = TimeSpan.FromMinutes(1);
            Func <string, bool> listenerFails = u => u == CallbackUriTemplate127001;

            var chooser = new LocalServerCodeReceiver.CallbackUriChooser(clock, timeout, listenerFails);

            // Loopback IP failed so this one is localhost.
            var uri1 = chooser.GetUriTemplate(LocalServerCodeReceiver.CallbackUriChooserStrategy.Default);

            // Make localhost time out.
            clock.UtcNow = clock.UtcNow.AddMinutes(2);
            // This one should still be localhost, which was timed out
            // vs loopback which was failed. And they have the same amount of reuses.
            var uri2 = chooser.GetUriTemplate(LocalServerCodeReceiver.CallbackUriChooserStrategy.Default);

            // Make it time out again.
            clock.UtcNow = clock.UtcNow.AddMinutes(2);
            // And now this should be loopback, it had less reuse.
            var uri3 = chooser.GetUriTemplate(LocalServerCodeReceiver.CallbackUriChooserStrategy.Default);

            Assert.Equal(CallbackUriTemplateLocalhost, uri1);
            Assert.Equal(CallbackUriTemplateLocalhost, uri2);

            Assert.Equal(CallbackUriTemplate127001, uri3);
        }
        public void CallbackUri_LoopbackReportedSuccess()
        {
            MockClock clock   = new MockClock(DateTime.UtcNow);
            TimeSpan  timeout = TimeSpan.FromMinutes(1);
            // All uris are good.
            Func <string, bool> listenerFails = u => false;

            var chooser = new LocalServerCodeReceiver.CallbackUriChooser(clock, timeout, listenerFails);

            var uri = chooser.GetUriTemplate(LocalServerCodeReceiver.CallbackUriChooserStrategy.Default);

            chooser.ReportSuccess(CallbackUriTemplate127001);

            var uri2 = chooser.GetUriTemplate(LocalServerCodeReceiver.CallbackUriChooserStrategy.Default);

            Assert.Equal(CallbackUriTemplate127001, uri2);

            // Even after time out
            clock.UtcNow = clock.UtcNow.AddMinutes(2);

            uri2 = chooser.GetUriTemplate(LocalServerCodeReceiver.CallbackUriChooserStrategy.Default);
            Assert.Equal(CallbackUriTemplate127001, uri2);

            // Even if a failure is reported, it succeeded at least once
            // so the failure is transient.
            chooser.ReportFailure(CallbackUriTemplate127001);

            uri2 = chooser.GetUriTemplate(LocalServerCodeReceiver.CallbackUriChooserStrategy.Default);
            Assert.Equal(CallbackUriTemplate127001, uri2);
        }
        public void CallbackUri_BothTimeout()
        {
            MockClock clock   = new MockClock(DateTime.UtcNow);
            TimeSpan  timeout = TimeSpan.FromMinutes(1);
            // All uris are good.
            Func <string, bool> listenerFails = u => false;

            var chooser = new LocalServerCodeReceiver.CallbackUriChooser(clock, timeout, listenerFails);

            // They should alternate based on the amount of reuse.
            var uri1 = chooser.GetUriTemplate(LocalServerCodeReceiver.CallbackUriChooserStrategy.Default);

            clock.UtcNow = clock.UtcNow.AddMinutes(2);
            var uri2 = chooser.GetUriTemplate(LocalServerCodeReceiver.CallbackUriChooserStrategy.Default);

            clock.UtcNow = clock.UtcNow.AddMinutes(2);
            var uri3 = chooser.GetUriTemplate(LocalServerCodeReceiver.CallbackUriChooserStrategy.Default);

            clock.UtcNow = clock.UtcNow.AddMinutes(2);
            var uri4 = chooser.GetUriTemplate(LocalServerCodeReceiver.CallbackUriChooserStrategy.Default);

            clock.UtcNow = clock.UtcNow.AddMinutes(2);

            Assert.Equal(CallbackUriTemplate127001, uri1);
            Assert.Equal(CallbackUriTemplate127001, uri3);

            Assert.Equal(CallbackUriTemplateLocalhost, uri2);
            Assert.Equal(CallbackUriTemplateLocalhost, uri4);
        }
Example #6
0
        public async Task FetchesOidcToken()
        {
            // A little bit after the tokens returned from OidcTokenFakes were issued.
            var clock          = new MockClock(new DateTime(2020, 5, 13, 15, 0, 0, 0, DateTimeKind.Utc));
            var messageHandler = new OidcTokenResponseSuccessMessageHandler();
            var initializer    = new ServiceAccountCredential.Initializer("MyId", "http://will.be.ignored")
            {
                Clock             = clock,
                ProjectId         = "a_project_id",
                HttpClientFactory = new MockHttpClientFactory(messageHandler)
            };
            var credential = new ServiceAccountCredential(initializer.FromPrivateKey(PrivateKey));

            // The fake Oidc server returns valid tokens (expired in the real world for safety)
            // but with a set audience that lets us know if the token was refreshed or not.
            var oidcToken = await credential.GetOidcTokenAsync(OidcTokenOptions.FromTargetAudience("will.be.ignored"));

            var signedToken = SignedToken <Header, Payload> .FromSignedToken(await oidcToken.GetAccessTokenAsync());

            Assert.Equal("https://first_call.test", signedToken.Payload.Audience);
            // Move the clock some but not enough that the token expires.
            clock.UtcNow = clock.UtcNow.AddMinutes(20);
            signedToken  = SignedToken <Header, Payload> .FromSignedToken(await oidcToken.GetAccessTokenAsync());

            Assert.Equal("https://first_call.test", signedToken.Payload.Audience);
            // Only the first call should have resulted in a request. The second time the token hadn't expired.
            Assert.Equal(1, messageHandler.Calls);
        }
Example #7
0
        public async Task RefreshesOidcToken()
        {
            // A little bit after the tokens returned from OidcTokenFakes were issued.
            var clock          = new MockClock(new DateTime(2020, 5, 13, 15, 0, 0, 0, DateTimeKind.Utc));
            var messageHandler = new OidcTokenResponseSuccessMessageHandler();
            var initializer    = new ServiceAccountCredential.Initializer("MyId", "http://will.be.ignored")
            {
                Clock             = clock,
                ProjectId         = "a_project_id",
                HttpClientFactory = new MockHttpClientFactory(messageHandler)
            };
            var credential = new ServiceAccountCredential(initializer.FromPrivateKey(PrivateKey));

            var oidcToken = await credential.GetOidcTokenAsync(OidcTokenOptions.FromTargetAudience("audience"));

            var signedToken = SignedToken <Header, Payload> .FromSignedToken(await oidcToken.GetAccessTokenAsync());

            Assert.Equal("https://first_call.test", signedToken.Payload.Audience);
            // Move the clock so that the token expires.
            clock.UtcNow = clock.UtcNow.AddHours(2);
            signedToken  = SignedToken <Header, Payload> .FromSignedToken(await oidcToken.GetAccessTokenAsync());

            Assert.Equal("https://subsequent_calls.test", signedToken.Payload.Audience);
            // Two calls, because the second time we tried to get the token, the first one had expired.
            Assert.Equal(2, messageHandler.Calls);
        }
Example #8
0
        private void VerifyPasswordResult(string correctPassword, string suppliedPassword, bool expectPasswordIsCorrect)
        {
            ReadRequestMessage readRequest = new ReadRequestMessage(new DateTime(0), suppliedPassword);

            using (BookmarkableStream clientStream = ClientRequestToStream(readRequest))
            {
                MockNetworkConnection networkConnection  = new MockNetworkConnection(clientStream);
                MockFolderPackager    mockFolderPackager = new MockFolderPackager();
                MockClock             serverClock        = new MockClock(new DateTime(2007, 5, 25, 15, 27, 03));

                RequestListener folderMonitor = new RequestListener(networkConnection, mockFolderPackager, serverClock, @"c:\fakepath\fakedir", correctPassword);
                folderMonitor.ProcessNextRequest();

                clientStream.ResetToBookmark();
                FarmerMessageSerializer deserializer = new FarmerMessageSerializer();
                ReadResponseMessage     readResponse = (ReadResponseMessage)deserializer.Deserialize(clientStream);

                Assert.AreEqual(expectPasswordIsCorrect, readResponse.IsPasswordCorrect);

                if (expectPasswordIsCorrect)
                {
                    Assert.AreEqual(serverClock.GetCurrentTimeUtc(), readResponse.CurrentServerTimeUtc);
                    Assert.IsNotNull(readResponse.Data);
                }
                else
                {
                    Assert.IsNull(readResponse.Data);
                }
            }
        }
Example #9
0
        public async Task JwtCache_Scoped_CachesOne()
        {
            var clock       = new MockClock(new DateTime(2016, 1, 1, 0, 0, 0, DateTimeKind.Utc));
            var initializer = new ServiceAccountCredential.Initializer("some-id")
            {
                UseJwtAccessWithScopes = true,
                Scopes = new[] { "scope1", "scope2" },
                Clock  = clock
            }.FromPrivateKey(PrivateKey);
            var cred = new ServiceAccountCredential(initializer);

            Assert.True(cred.HasExplicitScopes); // Must be true for the remainder of this test to be valid.
            Assert.True(cred.UseJwtAccessWithScopes);
            // Check that only one JWT is cached
            var jwt0 = await cred.GetAccessTokenForRequestAsync("uri0");

            for (int i = 0; i < ServiceAccountCredential.JwtCacheMaxSize; i++)
            {
                await cred.GetAccessTokenForRequestAsync($"uri{i}");

                // Check jwt is retrieved from cache.
                var jwt0Cached = await cred.GetAccessTokenForRequestAsync("uri0");

                Assert.Same(jwt0, jwt0Cached);
            }
            // Add one more JWT to cache that should remove jwt0 from the cache.
            await cred.GetAccessTokenForRequestAsync("uri_too_much");

            var jwt0Uncached = await cred.GetAccessTokenForRequestAsync("uri0");

            //  Scoped credential cache just one token regardless of authUri.
            Assert.Same(jwt0, jwt0Uncached);
        }
Example #10
0
        public async Task RetriesTimeout_Sync()
        {
            var clock = new MockClock {
                UtcNow = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Utc)
            };
            var logger              = new NullLogger();
            int refreshCallCount    = 0;
            int refreshCompleted    = 0;
            TokenRefreshManager trm = null;

            trm = new TokenRefreshManager(ct =>
            {
                Interlocked.Increment(ref refreshCallCount);
                Assert.True(ct.CanBeCanceled);
                new CancellationToken(true).ThrowIfCancellationRequested();
                // Will never get here
                Interlocked.Increment(ref refreshCompleted);
                return(Task.FromResult(false));
            }, clock, logger);

            var ex = await Assert.ThrowsAsync <InvalidOperationException>(() => trm.GetAccessTokenForRequestAsync(CancellationToken.None));

            Assert.Contains("timeout, timeout, timeout", ex.Message);
            Assert.Equal(TokenRefreshManager.RefreshTimeouts.Length, refreshCallCount);
            Assert.Equal(0, Interlocked.Add(ref refreshCompleted, 0));
        }
        public async Task RefreshesOidcToken()
        {
            // A little bit after the tokens returned from OidcTokenFakes were issued.
            var clock          = new MockClock(new DateTime(2020, 5, 21, 9, 20, 0, 0, DateTimeKind.Utc));
            var messageHandler = new OidcComputeSuccessMessageHandler();
            var initializer    = new ComputeCredential.Initializer("http://will.be.ignored", "http://will.be.ignored")
            {
                Clock             = clock,
                HttpClientFactory = new MockHttpClientFactory(messageHandler)
            };
            var credential = new ComputeCredential(initializer);

            // The fake Oidc server returns valid tokens (expired in the real world for safty)
            // but with a set audience that lets us know if the token was refreshed or not.
            var oidcToken = await credential.GetOidcTokenAsync(OidcTokenOptions.FromTargetAudience("will.be.ignored"));

            var signedToken = SignedToken <Header, Payload> .FromSignedToken(await oidcToken.GetAccessTokenAsync());

            Assert.Equal("https://first_call.test", signedToken.Payload.Audience);
            // Move the clock so that the token expires.
            clock.UtcNow = clock.UtcNow.AddHours(2);
            signedToken  = SignedToken <Header, Payload> .FromSignedToken(await oidcToken.GetAccessTokenAsync());

            Assert.Equal("https://subsequent_calls.test", signedToken.Payload.Audience);
            // Two calls, because the second time we tried to get the token, the first one had expired.
            Assert.Equal(2, messageHandler.Calls);
        }
        public async Task CreatesNewEntryWhenArticleFound()
        {
            var article          = new ArticleFixture().Build();
            var mockClock        = new MockClock();
            var dbContextFixture = new MockBlogApiDbContextFixture();

            dbContextFixture.Mock
            .Setup(ctx => ctx.Find <Article>(It.IsAny <Guid>()))
            .ReturnsAsync(() => article);

            var createArticleEntryCoordinator = new CreateArticleEntryCoordinatorFixture
            {
                Context = dbContextFixture.Build(),
                Clock   = mockClock
            }.Build();

            var result = await createArticleEntryCoordinator.CreateArticleEntry(article.Id, new ArticleEntry());

            Assert.Equal(article.Id, result.ArticleId);
            Assert.Equal(mockClock.Now, result.Created);

            dbContextFixture.Mock.Verify(ctx => ctx.Find <Article>(article.Id));
            dbContextFixture.Mock.Verify(ctx => ctx.Add(result));
            dbContextFixture.Mock.Verify(ctx => ctx.SaveChanges());
        }
        public async Task IncrementallyUpdatesArticleDataPartsWhenFound(Article existingArticle, ArticleRequest updatedArticle, Action <Article, ArticleRequest> validationAction)
        {
            var contextFixture = new MockBlogApiDbContextFixture();

            contextFixture.Mock
            .Setup(ctx => ctx.Find <Article>(existingArticle.Id))
            .Returns(async() =>
            {
                await Task.CompletedTask;
                return(existingArticle);
            });

            var clock = new MockClock();

            var coordinatorFixture = new UpdateArticleCoordinatorFixture
            {
                Context = contextFixture.Build(),
                Clock   = clock
            };

            var coordinator = coordinatorFixture.Build();

            Assert.False(existingArticle.Updated.HasValue);

            var result = await coordinator.TryUpdateArticle(existingArticle.Id, updatedArticle);

            contextFixture.Mock.Verify(ctx => ctx.Find <Article>(existingArticle.Id));
            contextFixture.Mock.Verify(ctx => ctx.SaveChanges());

            Assert.True(result);
            Assert.Equal(clock.Now, existingArticle.Updated.GetValueOrDefault());
            validationAction(existingArticle, updatedArticle);
        }
        public async Task Validate_Signature_Time()
        {
            var clockInvalid1 = new MockClock(FakeCertificateCache.BeforeValidJwtGoogleSigned);
            var clockValid1   = new MockClock(FakeCertificateCache.ValidJwtGoogleSigned);
            var clockInvalid2 = new MockClock(FakeCertificateCache.AfterValidJwtGoogleSigned);

            // Test with no tolerance
            Assert.NotNull(await GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clockValid1)));

            var ex1 = await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                                     GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clockInvalid1)));

            Assert.Equal("JWT is not yet valid.", ex1.Message);

            var ex2 = await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                                     GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clockInvalid2)));

            Assert.Equal("JWT has expired.", ex2.Message);

            // Test with tolerance
            await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                           GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clockInvalid1, clockToleranceSeconds: 109)));

            Assert.NotNull(await GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clockInvalid1, clockToleranceSeconds: 111)));
            Assert.NotNull(await GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clockInvalid2, clockToleranceSeconds: 11)));
            await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                           GoogleJsonWebSignature.ValidateInternalAsync(FakeCertificateCache.JwtGoogleSigned, MakeSettings(clockInvalid2, clockToleranceSeconds: 9)));
        }
        public async Task SavesNewEntryWhenConditionsMeet()
        {
            var blog            = new BlogFixture().Build();
            var newEntryRequest = new ArticleRequest
            {
                BlogId      = blog.Id,
                Author      = "Test",
                Title       = "Some-title",
                Description = "some-Description",
            };

            var dbContextFixture = new MockBlogApiDbContextFixture().With(blog, blog.Id);
            var clock            = new MockClock();

            var blogEntryCoordinator = new CreateArticleCoordinatorFixture()
            {
                Context = dbContextFixture.Build(),
                Clock   = clock
            }.Build();

            var result = await blogEntryCoordinator.CreateNewArticleAsync(newEntryRequest);

            Assert.Equal(newEntryRequest.BlogId, result.BlogId);
            Assert.Equal(newEntryRequest.Author, result.Author);
            Assert.Equal(newEntryRequest.Title, result.Title);
            Assert.Equal(newEntryRequest.Description, result.Description);
            Assert.Equal(clock.Now, result.Created);

            dbContextFixture.Mock.Verify(ctx => ctx.Add(result));
            dbContextFixture.Mock.Verify(ctx => ctx.SaveChanges());
        }
Example #16
0
        public async Task FromResponse_TokenResponse()
        {
            TokenResponse sentToken = new TokenResponse
            {
                IdToken          = "IdToken",
                AccessToken      = "AccessToken",
                RefreshToken     = "RefreshToken",
                Scope            = "Scope",
                TokenType        = "TokenType",
                ExpiresInSeconds = 100,
                // It really doesn't matter, we always set it to now when the token is received
                // because that's the recommendation.
                IssuedUtc = new DateTime(2000, 01, 01, 0, 0, 0, DateTimeKind.Utc),
            };
            var serializedToken          = NewtonsoftJsonSerializer.Instance.Serialize(sentToken);
            HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK)
            {
                Content = new StringContent(serializedToken)
            };

            MockClock     clock = new MockClock(new DateTime(2020, 02, 02, 2, 20, 20, DateTimeKind.Utc));
            TokenResponse token = await TokenResponse.FromHttpResponseAsync(response, clock, new NullLogger());

            Assert.Equal("IdToken", token.IdToken);
            Assert.Equal("AccessToken", token.AccessToken);
            Assert.Equal("RefreshToken", token.RefreshToken);
            Assert.Equal("Scope", token.Scope);
            Assert.Equal("TokenType", token.TokenType);
            Assert.Equal(100, token.ExpiresInSeconds);
            // The date should be our mock now, not the one set on the sent token.
            Assert.Equal(new DateTime(2020, 02, 02, 2, 20, 20, DateTimeKind.Utc), token.IssuedUtc);
        }
Example #17
0
        public void IfNoErrorIsRecordedThenTimeoutHasNoInnerException()
        {
            var clock    = new MockClock(DateTimeOffset.Now);
            var deadline = new Deadline(clock, TimeSpan.FromMinutes(5));

            Assert.That(deadline.Timeout().InnerException, Is.Null);
        }
        public async Task NetworkError()
        {
            var clock   = new MockClock();
            var handler = new MockMessageHandler()
            {
                Exception = new HttpRequestException("Network error"),
            };
            var clientFactory = new MockHttpClientFactory(handler);
            var keyManager    = new HttpPublicKeySource(
                "https://example.com/certs", clock, clientFactory);

            var exception = await Assert.ThrowsAsync <FirebaseAuthException>(
                async() => await keyManager.GetPublicKeysAsync());

            Assert.Equal(ErrorCode.Unknown, exception.ErrorCode);
            Assert.Equal(
                "Failed to retrieve latest public keys. Unknown error while making a remote "
                + "service call: Network error",
                exception.Message);
            Assert.Equal(AuthErrorCode.CertificateFetchFailed, exception.AuthErrorCode);
            Assert.Null(exception.HttpResponse);
            Assert.Same(handler.Exception, exception.InnerException);

            Assert.Equal(1, handler.Calls);
        }
Example #19
0
        public EndToEndTests()
        {
            //This path is used to save in memory storage
            var strTempDataFolderPath = AppDomain.CurrentDomain.BaseDirectory + @"App_Data\";

            //create temp directory if it doesn't exist
            new FileInfo(strTempDataFolderPath).Directory?.Create();

            var inMemoryEventStorePath    = $@"{strTempDataFolderPath}events.stream.dump";
            var inMemorySnapshotStorePath = $@"{strTempDataFolderPath}events.snapshot.dump";

            File.Delete(inMemoryEventStorePath);
            File.Delete(inMemorySnapshotStorePath);

            IEventStorageProvider <Guid> eventStorage =
                new InMemoryEventStorageProvider(inMemoryEventStorePath);

            ISnapshotStorageProvider <Guid> snapshotStorage =
                new InMemorySnapshotStorageProvider(SnapshotFrequency, inMemorySnapshotStorePath);

            _clock               = new MockClock();
            _eventPublisher      = new MockEventPublisher();
            _repository          = new Repository <Schedule, ScheduleSnapshot, Guid, Guid, Guid>(_clock, eventStorage, _eventPublisher, snapshotStorage);
            _eventOnlyRepository = new EventOnlyRepository <Schedule, Guid, Guid>(_clock, eventStorage, _eventPublisher);
        }
        public async Task HttpError()
        {
            var clock   = new MockClock();
            var handler = new MockMessageHandler()
            {
                StatusCode = HttpStatusCode.InternalServerError,
                Response   = "test error",
            };
            var clientFactory = new MockHttpClientFactory(handler);
            var keyManager    = new HttpPublicKeySource(
                "https://example.com/certs", clock, clientFactory);

            var exception = await Assert.ThrowsAsync <FirebaseAuthException>(
                async() => await keyManager.GetPublicKeysAsync());

            Assert.Equal(ErrorCode.Internal, exception.ErrorCode);
            Assert.Equal(
                "Unexpected HTTP response with status: 500 (InternalServerError)\ntest error",
                exception.Message);
            Assert.Equal(AuthErrorCode.CertificateFetchFailed, exception.AuthErrorCode);
            Assert.NotNull(exception.HttpResponse);
            Assert.Null(exception.InnerException);

            Assert.Equal(1, handler.Calls);
        }
Example #21
0
        public async Task RetryAfterTimestamp()
        {
            var clock     = new MockClock();
            var timestamp = clock.UtcNow.AddSeconds(4).ToString("r");
            var handler   = new MockMessageHandler()
            {
                StatusCode   = HttpStatusCode.ServiceUnavailable,
                ApplyHeaders = (headers, contentHeaders) =>
                {
                    headers.RetryAfter = RetryConditionHeaderValue.Parse(timestamp);
                },
                Response = "{}",
            };
            var waiter     = new MockWaiter();
            var httpClient = CreateHttpClient(handler, RetryOptions.Default, waiter, clock);

            var response = await httpClient.SendAsync(CreateRequest());

            Assert.Equal(HttpStatusCode.ServiceUnavailable, response.StatusCode);
            Assert.Equal(5, handler.Calls);
            Assert.Equal(4, waiter.WaitTimes.Count);
            foreach (var timespan in waiter.WaitTimes)
            {
                // Due to the date format used in HTTP headers, the milliseconds precision gets
                // lost. Therefore the actual delay is going to be a value between 3 and 4 seconds.
                Assert.True(timespan.TotalSeconds > 3.0 && timespan.TotalSeconds <= 4.0);
            }
        }
        public async Task AccessTokenWithHeadersCredential()
        {
            var mockClock     = new MockClock();
            var tokenResponse = new TokenResponse
            {
                AccessToken      = "ACCESS_TOKEN",
                ExpiresInSeconds = 60 * 10,
                IssuedUtc        = DateTime.Now,
                RefreshToken     = "REFRESH_TOKEN",
            };
            var flowMock = new Mock <IAuthorizationCodeFlow>(MockBehavior.Strict);

            flowMock
            .Setup(flow => flow.Clock)
            .Returns(mockClock);
            flowMock
            .Setup(flow => flow.AccessMethod)
            .Returns(new AuthorizationHeaderAccessMethod());

            var         userCred = new UserCredential(flowMock.Object, "USER_ID", tokenResponse, "QUOTA_PROJECT");
            ICredential cred     = new GoogleCredential(userCred);

            var httpHandler = new FakeHandler();
            var httpClient  = new Http.ConfigurableHttpClient(new Http.ConfigurableMessageHandler(httpHandler));

            cred.Initialize(httpClient);
            await httpClient.GetAsync("http://localhost/TestRequest");

            Assert.Equal("Bearer", httpHandler.RequestHeaders.Authorization.Scheme);
            Assert.Equal("ACCESS_TOKEN", httpHandler.RequestHeaders.Authorization.Parameter);

            Assert.True(httpHandler.RequestHeaders.TryGetValues("x-goog-user-project", out var values));
            Assert.Single(values);
            Assert.Equal("QUOTA_PROJECT", values.First());
        }
Example #23
0
        public async Task Validate_Signature_Time()
        {
            var clockInvalid1 = new MockClock()
            {
                UtcNow = new DateTime(2017, 5, 31, 10, 22, 0, DateTimeKind.Utc)
            };
            var clockValid1 = new MockClock()
            {
                UtcNow = new DateTime(2017, 5, 31, 10, 24, 0, DateTimeKind.Utc)
            };
            var clockValid2 = new MockClock()
            {
                UtcNow = new DateTime(2017, 5, 31, 11, 22, 0, DateTimeKind.Utc)
            };
            var clockInvalid2 = new MockClock()
            {
                UtcNow = new DateTime(2017, 5, 31, 11, 24, 0, DateTimeKind.Utc)
            };

            Assert.NotNull(await GoogleJsonWebSignature.ValidateInternalAsync(JwtGoogleSigned, MakeSettings(clockValid1), GoogleCertsJson, false));
            Assert.NotNull(await GoogleJsonWebSignature.ValidateInternalAsync(JwtGoogleSigned, MakeSettings(clockValid2), GoogleCertsJson, false));

            var ex1 = await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                                     GoogleJsonWebSignature.ValidateInternalAsync(JwtGoogleSigned, MakeSettings(clockInvalid1), GoogleCertsJson, false));

            Assert.Equal("JWT is not yet valid.", ex1.Message);

            var ex2 = await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                                     GoogleJsonWebSignature.ValidateInternalAsync(JwtGoogleSigned, MakeSettings(clockInvalid2), GoogleCertsJson, false));

            Assert.Equal("JWT has expired.", ex2.Message);
        }
Example #24
0
        public async Task Validate_CertCache()
        {
            var clock1 = new MockClock()
            {
                UtcNow = new DateTime(2017, 5, 31, 11, 24, 0, DateTimeKind.Utc)
            };
            var clock2Cached = new MockClock()
            {
                UtcNow = clock1.UtcNow + GoogleJsonWebSignature.CertCacheRefreshInterval - TimeSpan.FromSeconds(1)
            };
            var clock3Uncached = new MockClock()
            {
                UtcNow = clock1.UtcNow + GoogleJsonWebSignature.CertCacheRefreshInterval + TimeSpan.FromSeconds(1)
            };

            var rsas1 = await GoogleJsonWebSignature.GetGoogleCertsAsync(clock1, false, GoogleCertsJson);

            var rsas2Cached = await GoogleJsonWebSignature.GetGoogleCertsAsync(clock2Cached, false, GoogleCertsJson);

            var rsas3Refreshed = await GoogleJsonWebSignature.GetGoogleCertsAsync(clock3Uncached, false, GoogleCertsJson);

            var rsas4Forced = await GoogleJsonWebSignature.GetGoogleCertsAsync(clock3Uncached, true, GoogleCertsJson);

            Assert.NotNull(rsas1);
            Assert.Same(rsas1, rsas2Cached);
            Assert.NotSame(rsas1, rsas3Refreshed);
            Assert.NotSame(rsas3Refreshed, rsas4Forced);
        }
Example #25
0
        public async Task JwtCache_Size()
        {
            var clock = new MockClock {
                UtcNow = new DateTime(2016, 1, 1, 0, 0, 0, DateTimeKind.Utc)
            };
            var initializer = new ServiceAccountCredential.Initializer("some-id")
            {
                Clock = clock
            }.FromPrivateKey(PrivateKey);
            var cred = new ServiceAccountCredential(initializer);

            Assert.False(cred.HasScopes); // Must be false for the remainder of this test to be valid.
            // Check JWTs removed from cache once cache fills up.
            var jwt0 = await cred.GetAccessTokenForRequestAsync("uri0");

            for (int i = 0; i < ServiceAccountCredential.JwtCacheMaxSize; i++)
            {
                await cred.GetAccessTokenForRequestAsync($"uri{i}");

                // Check jwt is retrieved from cache.
                var jwt0Cached = await cred.GetAccessTokenForRequestAsync("uri0");

                Assert.Same(jwt0, jwt0Cached);
            }
            // Add one more JWT to cache that should remove jwt0 from the cache.
            await cred.GetAccessTokenForRequestAsync("uri_too_much");

            var jwt0Uncached = await cred.GetAccessTokenForRequestAsync("uri0");

            Assert.NotSame(jwt0, jwt0Uncached);
        }
        public async Task Validate_Signature_Time()
        {
            var clockInvalid1 = new MockClock(FakeCertificateCache.BeforeValidJwtGoogleSigned);
            var clockValid1   = new MockClock(FakeCertificateCache.ValidJwtGoogleSigned);
            var clockInvalid2 = new MockClock(FakeCertificateCache.AfterValidJwtGoogleSigned);

            // Test with no tolerance
            Assert.NotNull(await JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockValid1)));

            var ex1 = await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                                     JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid1)));

            Assert.Equal("JWT is not yet valid.", ex1.Message);

            var ex2 = await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                                     JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid2)));

            Assert.Equal("JWT has expired.", ex2.Message);

            // Test with tolerance
            await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                           JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid1, clockTolerance: TimeSpan.FromSeconds(109))));

            Assert.NotNull(await JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid1, clockTolerance: TimeSpan.FromSeconds(111))));
            Assert.NotNull(await JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid2, clockTolerance: TimeSpan.FromSeconds(11))));
            await Assert.ThrowsAsync <InvalidJwtException>(() =>
                                                           JsonWebSignature.VerifySignedTokenAsync(FakeCertificateCache.JwtGoogleSigned, BuildOptions(clockInvalid2, clockTolerance: TimeSpan.FromSeconds(9))));
        }
Example #27
0
        public async Task UnobservedException()
        {
            // An unobserved exception used to happen when the token is soft expired so that
            // a refresh token task is started but not inmediately observed and it fails.
            // See https://github.com/googleapis/google-api-dotnet-client/issues/2021
            string exceptionMessage = "While testing for unobserved exceptions the refresh task failed.";
            int    unobservedCount  = 0;

            TaskScheduler.UnobservedTaskException += (sender, e) =>
            {
                if (e.Exception.InnerExceptions.Any(ex => ex.Message == exceptionMessage))
                {
                    Interlocked.Increment(ref unobservedCount);
                    e.SetObserved();
                }
            };

            var refreshCompletionSource = new TaskCompletionSource <bool>();
            var clock            = new MockClock(new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Utc));
            var logger           = new NullLogger();
            var softExpiredToken = new TokenResponse
            {
                AccessToken      = clock.UtcNow.ToString("O"),
                ExpiresInSeconds = TokenResponse.TokenRefreshTimeWindowSeconds,
                IssuedUtc        = clock.UtcNow
            };
            TokenRefreshManager trm = new TokenRefreshManager(ThrowsWhenRefreshing, clock, logger)
            {
                // The initial token is soft expired.
                Token = softExpiredToken
            };

            // Since the token is only soft expired, we will get it, but a refresh task
            // is still started.
            var token = await trm.GetAccessTokenForRequestAsync(default);
Example #28
0
        public async Task RetriesTimeout_Async()
        {
            var clock               = new MockClock(new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Utc));
            var logger              = new NullLogger();
            int refreshCallCount    = 0;
            int refreshCompleted    = 0;
            TokenRefreshManager trm = null;

            trm = new TokenRefreshManager(async ct =>
            {
                Interlocked.Increment(ref refreshCallCount);
                Assert.True(ct.CanBeCanceled);
                var token = new CancellationTokenSource(TimeSpan.FromMilliseconds(10)).Token;
                await Task.Delay(TimeSpan.FromSeconds(10), token);
                // Will never get here
                Interlocked.Increment(ref refreshCompleted);
                return(false);
            }, clock, logger);

            var ex = await Assert.ThrowsAsync <InvalidOperationException>(() => trm.GetAccessTokenForRequestAsync(CancellationToken.None));

            Assert.Contains("timeout, timeout, timeout", ex.Message);
            Assert.Equal(TokenRefreshManager.RefreshTimeouts.Length, refreshCallCount);
            Assert.Equal(0, Interlocked.Add(ref refreshCompleted, 0));
        }
Example #29
0
        public async Task CancelDuringRefresh()
        {
            var clock               = new MockClock(new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Utc));
            var logger              = new NullLogger();
            int refreshCalled       = 0;
            int refreshCompleted    = 0;
            var refreshCts          = new CancellationTokenSource();
            TokenRefreshManager trm = null;

            trm = new TokenRefreshManager(async ct =>
            {
                Interlocked.Increment(ref refreshCalled);
                await Task.Delay(TimeSpan.FromSeconds(60), refreshCts.Token);
                // Will never get here
                Interlocked.Increment(ref refreshCompleted);
                return(false);
            }, clock, logger);

            var cts = new CancellationTokenSource(TimeSpan.FromMilliseconds(10));
            await Assert.ThrowsAsync <TaskCanceledException>(() => trm.GetAccessTokenForRequestAsync(cts.Token));

            refreshCts.Cancel();

            // Non-deterministic if the refresh function gets called by the time this test ends.
            // And it's either be called never, or retried n times by the token refresh manager.
            Assert.InRange(Interlocked.Add(ref refreshCalled, 0), 0, TokenRefreshManager.RefreshTimeouts.Length);
            Assert.Equal(0, Interlocked.Add(ref refreshCompleted, 0));
        }
Example #30
0
        public async Task ExpiredToken()
        {
            var    clock            = new MockClock(new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Utc));
            var    logger           = new NullLogger();
            int    refreshFnCount   = 0;
            string accessToken      = null;
            TokenRefreshManager trm = null;

            trm = new TokenRefreshManager(ct =>
            {
                trm.Token = new TokenResponse
                {
                    AccessToken      = accessToken,
                    ExpiresInSeconds = 60 * 60,
                    IssuedUtc        = clock.UtcNow
                };
                Interlocked.Increment(ref refreshFnCount);
                return(Task.FromResult(true));
            }, clock, logger);

            accessToken = "AccessToken1";
            var accessToken1 = await trm.GetAccessTokenForRequestAsync(CancellationToken.None);

            clock.UtcNow += TimeSpan.FromHours(24);
            accessToken   = "AccessToken2";
            var accessToken2 = await trm.GetAccessTokenForRequestAsync(CancellationToken.None);

            Assert.Equal(2, Interlocked.Add(ref refreshFnCount, 0));
            Assert.Equal("AccessToken1", accessToken1);
            Assert.Equal("AccessToken2", accessToken2);
        }
Example #31
0
        public void TestDebounce()
        {
            uint count = 0;
            MockClock mc = new MockClock();
            ButtonPressCounter counter = new ButtonPressCounter(mc, TimeSpan.FromMilliseconds(10), TimeSpan.FromMilliseconds(50));

            counter.OnButtonStreamComplete += (c) => count = c;
            mc.Start();

            counter.RecordPress();
            counter.RecordPress();
            counter.RecordPress();
            Thread.Sleep(100);
            Assert.AreEqual<uint>(1, count);
            mc.Stop();
        }
Example #32
0
        public void TestStream()
        {
            MockClock mc = new MockClock();

            uint count = 0;
            ButtonPressCounter counter = new ButtonPressCounter(mc, TimeSpan.FromMilliseconds(10), TimeSpan.FromMilliseconds(100));

            counter.OnButtonStreamComplete += (c) => count = c;
            mc.Start();

            counter.RecordPress();
            Thread.Sleep(11);
            counter.RecordPress();
            Thread.Sleep(11);
            Assert.AreEqual(0u, count);
            Thread.Sleep(300);
            Assert.AreEqual(2u, count);
            mc.Stop();
        }