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); }
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); }
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); }
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); } } }
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); }
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()); }
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); }
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); }
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); }
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()); }
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); }
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); }
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)))); }
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);
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)); }
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)); }
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); }
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(); }
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(); }