public void AbsoluteExpirationExpiresInBackground() { var clock = new TestClock(); var cache = CreateCache(clock); var key = "myKey"; var value = new object(); var callbackInvoked = new ManualResetEvent(false); var options = new MemoryCacheEntryOptions() .SetAbsoluteExpiration(clock.UtcNow + TimeSpan.FromMinutes(1)) .RegisterPostEvictionCallback((subkey, subValue, reason, state) => { // TODO: Verify params var localCallbackInvoked = (ManualResetEvent)state; localCallbackInvoked.Set(); }, callbackInvoked); var result = cache.Set(key, value, options); Assert.Same(value, result); var found = cache.TryGetValue(key, out result); Assert.True(found); Assert.Same(value, result); clock.Add(TimeSpan.FromMinutes(2)); var ignored = cache.Get("otherKey"); // Background expiration checks are triggered by misc cache activity. Assert.True(callbackInvoked.WaitOne(100), "Callback"); found = cache.TryGetValue(key, out result); Assert.False(found); Assert.Null(result); }
public void AbsoluteExpirationInThePastThrows() { var clock = new TestClock(); var cache = CreateCache(clock); var key = "myKey"; var obj = new object(); var expected = clock.UtcNow - TimeSpan.FromMinutes(1); ExceptionAssert.ThrowsArgumentOutOfRange(() => { var result = cache.Set(key, obj, new MemoryCacheEntryOptions().SetAbsoluteExpiration(expected)); }, nameof(MemoryCacheEntryOptions.AbsoluteExpiration), "The absolute expiration value must be in the future.", expected.ToString(CultureInfo.CurrentCulture)); }
public void AbsoluteExpirationExpires() { var clock = new TestClock(); var cache = CreateCache(clock); var key = "myKey"; var value = new object(); var result = cache.Set(key, value, new MemoryCacheEntryOptions() .SetAbsoluteExpiration(clock.UtcNow + TimeSpan.FromMinutes(1))); Assert.Same(value, result); var found = cache.TryGetValue(key, out result); Assert.True(found); Assert.Same(value, result); clock.Add(TimeSpan.FromMinutes(2)); found = cache.TryGetValue(key, out result); Assert.False(found); Assert.Null(result); }
public void SlidingExpirationRenewedByAccessUntilAbsoluteExpiration() { var clock = new TestClock(); var cache = CreateCache(clock); var key = "myKey"; var value = new object(); var result = cache.Set(key, value, new MemoryCacheEntryOptions() .SetSlidingExpiration(TimeSpan.FromMinutes(1)) .SetAbsoluteExpiration(TimeSpan.FromMinutes(2))); Assert.Same(value, result); var found = cache.TryGetValue(key, out result); Assert.True(found); Assert.Same(value, result); for (int i = 0; i < 7; i++) { clock.Add(TimeSpan.FromSeconds(15)); found = cache.TryGetValue(key, out result); Assert.True(found); Assert.Same(value, result); } clock.Add(TimeSpan.FromSeconds(15)); found = cache.TryGetValue(key, out result); Assert.False(found); Assert.Null(result); }
public async Task RefreshesSession_WhenSessionData_IsNotModified() { var clock = new TestClock(); using (var server = TestServer.Create(app => { app.UseSession(); app.Run(context => { string responseData = string.Empty; if (context.Request.Path == new PathString("/AddDataToSession")) { context.Session.SetInt32("Key", 10); responseData = "added data to session"; } else if (context.Request.Path == new PathString("/AccessSessionData")) { var value = context.Session.GetInt32("Key"); responseData = (value == null) ? "No value found in session." : value.ToString(); } else if (context.Request.Path == new PathString("/DoNotAccessSessionData")) { responseData = "did not access session data"; } return context.Response.WriteAsync(responseData); }); }, services => { services.AddInstance(typeof(ILoggerFactory), new NullLoggerFactory()); services.AddCaching(); services.AddSession(); services.ConfigureSession(o => o.IdleTimeout = TimeSpan.FromMinutes(20)); services.Configure<MemoryCacheOptions>(o => o.Clock = clock); })) { var client = server.CreateClient(); var response = await client.GetAsync("AddDataToSession"); response.EnsureSuccessStatusCode(); client = server.CreateClient(); var cookie = SetCookieHeaderValue.ParseList(response.Headers.GetValues("Set-Cookie").ToList()).First(); client.DefaultRequestHeaders.Add( "Cookie", new CookieHeaderValue(cookie.Name, cookie.Value).ToString()); for (var i = 0; i < 5; i++) { clock.Add(TimeSpan.FromMinutes(10)); await client.GetStringAsync("/DoNotAccessSessionData"); } var data = await client.GetStringAsync("/AccessSessionData"); Assert.Equal("10", data); } }
public async Task CookieChallengeWithUnauthorizedRedirectsToLoginIfNotAuthenticated() { var clock = new TestClock(); var server = CreateServer(options => { options.SystemClock = clock; options.LoginPath = new PathString("/page"); }); var transaction1 = await SendAsync(server, "http://example.com/testpath"); var transaction2 = await SendAsync(server, "http://example.com/unauthorized", transaction1.CookieNameValue); transaction2.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); }
public async Task CookieTurns401ToAccessDeniedWhenSetWithCookie() { var clock = new TestClock(); var server = CreateServer(options => { options.SystemClock = clock; options.AccessDeniedPath = new PathString("/accessdenied"); }, SignInAsAlice); var transaction1 = await SendAsync(server, "http://example.com/testpath"); var transaction2 = await SendAsync(server, "http://example.com/challenge", transaction1.CookieNameValue); transaction2.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); var location = transaction2.Response.Headers.Location; location.LocalPath.ShouldBe("/accessdenied"); }
public async Task CookieAppliesClaimsTransform() { var clock = new TestClock(); var server = CreateServer(options => { options.SystemClock = clock; }, SignInAsAlice, baseAddress: null, claimsTransform: o => o.Transformer = new ClaimsTransformer { TransformSyncDelegate = p => { if (!p.Identities.Any(i => i.AuthenticationType == "xform")) { var id = new ClaimsIdentity("xform"); id.AddClaim(new Claim("sync", "no")); p.AddIdentity(id); } return p; }, TransformAsyncDelegate = p => { if (!p.Identities.Any(i => i.AuthenticationType == "xform")) { // REVIEW: Xform runs twice, once on Authenticate, and then once from the middleware var id = new ClaimsIdentity("xform"); id.AddClaim(new Claim("xform", "yup")); p.AddIdentity(id); } return Task.FromResult(p); } }); var transaction1 = await SendAsync(server, "http://example.com/testpath"); var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); FindClaimValue(transaction2, ClaimTypes.Name).ShouldBe("Alice"); FindClaimValue(transaction2, "xform").ShouldBe("yup"); FindClaimValue(transaction2, "sync").ShouldBe(null); }
public async Task CookieUsesPathBaseByDefault() { var clock = new TestClock(); var server = CreateServer(options => { }, context => { Assert.Equal(new PathString("/base"), context.Request.PathBase); return context.Authentication.SignInAsync("Cookies", new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies")))); }, new Uri("http://example.com/base")); var transaction1 = await SendAsync(server, "http://example.com/base/testpath"); Assert.True(transaction1.SetCookie.Contains("path=/base")); }
public async Task CookieIsRenewedWithSlidingExpiration() { var clock = new TestClock(); var server = CreateServer(options => { options.SystemClock = clock; options.ExpireTimeSpan = TimeSpan.FromMinutes(10); options.SlidingExpiration = true; }, SignInAsAlice); var transaction1 = await SendAsync(server, "http://example.com/testpath"); var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); transaction2.SetCookie.ShouldBe(null); FindClaimValue(transaction2, ClaimTypes.Name).ShouldBe("Alice"); clock.Add(TimeSpan.FromMinutes(4)); var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); transaction3.SetCookie.ShouldBe(null); FindClaimValue(transaction3, ClaimTypes.Name).ShouldBe("Alice"); clock.Add(TimeSpan.FromMinutes(4)); // transaction4 should arrive with a new SetCookie value var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); transaction4.SetCookie.ShouldNotBe(null); FindClaimValue(transaction4, ClaimTypes.Name).ShouldBe("Alice"); clock.Add(TimeSpan.FromMinutes(4)); var transaction5 = await SendAsync(server, "http://example.com/me/Cookies", transaction4.CookieNameValue); transaction5.SetCookie.ShouldBe(null); FindClaimValue(transaction5, ClaimTypes.Name).ShouldBe("Alice"); }
public async Task CookieExpirationCanBeOverridenInEvent() { var clock = new TestClock(); var server = CreateServer(options => { options.SystemClock = clock; options.ExpireTimeSpan = TimeSpan.FromMinutes(10); options.SlidingExpiration = false; options.Notifications = new CookieAuthenticationNotifications() { OnResponseSignIn = context => { context.Properties.ExpiresUtc = clock.UtcNow.Add(TimeSpan.FromMinutes(5)); } }; }, SignInAsAlice); var transaction1 = await SendAsync(server, "http://example.com/testpath"); var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); transaction2.SetCookie.ShouldBe(null); FindClaimValue(transaction2, ClaimTypes.Name).ShouldBe("Alice"); clock.Add(TimeSpan.FromMinutes(3)); var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); transaction3.SetCookie.ShouldBe(null); FindClaimValue(transaction3, ClaimTypes.Name).ShouldBe("Alice"); clock.Add(TimeSpan.FromMinutes(3)); var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); transaction4.SetCookie.ShouldBe(null); FindClaimValue(transaction4, ClaimTypes.Name).ShouldBe(null); }
public async Task CookieCanBeRenewedByValidatorWithSlidingExpiry() { var clock = new TestClock(); var server = CreateServer(options => { options.SystemClock = clock; options.ExpireTimeSpan = TimeSpan.FromMinutes(10); options.Notifications = new CookieAuthenticationNotifications { OnValidatePrincipal = ctx => { ctx.ShouldRenew = true; return Task.FromResult(0); } }; }, context => context.Authentication.SignInAsync("Cookies", new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))))); var transaction1 = await SendAsync(server, "http://example.com/testpath"); var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); transaction2.SetCookie.ShouldNotBe(null); FindClaimValue(transaction2, ClaimTypes.Name).ShouldBe("Alice"); clock.Add(TimeSpan.FromMinutes(5)); var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction2.CookieNameValue); transaction3.SetCookie.ShouldNotBe(null); FindClaimValue(transaction3, ClaimTypes.Name).ShouldBe("Alice"); clock.Add(TimeSpan.FromMinutes(6)); var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction3.CookieNameValue); transaction4.SetCookie.ShouldNotBe(null); FindClaimValue(transaction4, ClaimTypes.Name).ShouldBe("Alice"); clock.Add(TimeSpan.FromMinutes(11)); var transaction5 = await SendAsync(server, "http://example.com/me/Cookies", transaction4.CookieNameValue); transaction5.SetCookie.ShouldBe(null); FindClaimValue(transaction5, ClaimTypes.Name).ShouldBe(null); }
public async Task CookieCanBeRejectedAndSignedOutByValidator() { var clock = new TestClock(); var server = CreateServer(options => { options.SystemClock = clock; options.ExpireTimeSpan = TimeSpan.FromMinutes(10); options.SlidingExpiration = false; options.Notifications = new CookieAuthenticationNotifications { OnValidatePrincipal = ctx => { ctx.RejectPrincipal(); ctx.HttpContext.Authentication.SignOutAsync("Cookies"); return Task.FromResult(0); } }; }, context => context.Authentication.SignInAsync("Cookies", new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))))); var transaction1 = await SendAsync(server, "http://example.com/testpath"); var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); transaction2.SetCookie.ShouldContain(".AspNet.Cookies=; expires="); FindClaimValue(transaction2, ClaimTypes.Name).ShouldBe(null); }
public async Task CookieExpirationCanBeOverridenInSignin() { var clock = new TestClock(); var server = CreateServer(options => { options.SystemClock = clock; options.ExpireTimeSpan = TimeSpan.FromMinutes(10); options.SlidingExpiration = false; }, context => context.Authentication.SignInAsync("Cookies", new ClaimsPrincipal(new ClaimsIdentity(new GenericIdentity("Alice", "Cookies"))), new AuthenticationProperties() { ExpiresUtc = clock.UtcNow.Add(TimeSpan.FromMinutes(5)) })); var transaction1 = await SendAsync(server, "http://example.com/testpath"); var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); clock.Add(TimeSpan.FromMinutes(3)); var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); clock.Add(TimeSpan.FromMinutes(3)); var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); transaction2.SetCookie.ShouldBe(null); FindClaimValue(transaction2, ClaimTypes.Name).ShouldBe("Alice"); transaction3.SetCookie.ShouldBe(null); FindClaimValue(transaction3, ClaimTypes.Name).ShouldBe("Alice"); transaction4.SetCookie.ShouldBe(null); FindClaimValue(transaction4, ClaimTypes.Name).ShouldBe(null); }
public async Task CookieStopsWorkingAfterExpiration() { var clock = new TestClock(); var server = CreateServer(options => { options.SystemClock = clock; options.ExpireTimeSpan = TimeSpan.FromMinutes(10); options.SlidingExpiration = false; }, SignInAsAlice); var transaction1 = await SendAsync(server, "http://example.com/testpath"); var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); clock.Add(TimeSpan.FromMinutes(7)); var transaction3 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); clock.Add(TimeSpan.FromMinutes(7)); var transaction4 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); transaction2.SetCookie.ShouldBe(null); FindClaimValue(transaction2, ClaimTypes.Name).ShouldBe("Alice"); transaction3.SetCookie.ShouldBe(null); FindClaimValue(transaction3, ClaimTypes.Name).ShouldBe("Alice"); transaction4.SetCookie.ShouldBe(null); FindClaimValue(transaction4, ClaimTypes.Name).ShouldBe(null); }
public void ZeroSlidingExpirationThrows() { var clock = new TestClock(); var cache = CreateCache(clock); var key = "myKey"; var value = new object(); ExceptionAssert.ThrowsArgumentOutOfRange(() => { var result = cache.Set(key, value, new MemoryCacheEntryOptions() .SetSlidingExpiration(TimeSpan.Zero)); }, nameof(MemoryCacheEntryOptions.SlidingExpiration), "The sliding expiration value must be positive.", TimeSpan.Zero); }
public async Task CookieTurnsChallengeIntoForbidWithCookie(bool automatic) { var clock = new TestClock(); var server = CreateServer(options => { options.AutomaticAuthentication = automatic; options.SystemClock = clock; }, SignInAsAlice); var transaction1 = await SendAsync(server, "http://example.com/testpath"); var url = "http://example.com/challenge"; var transaction2 = await SendAsync(server, url, transaction1.CookieNameValue); transaction2.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); var location = transaction2.Response.Headers.Location; location.LocalPath.ShouldBe("/Account/AccessDenied"); }
public async Task CookieForbidRedirectsWithoutCookie(bool automatic) { var clock = new TestClock(); var server = CreateServer(options => { options.AutomaticAuthentication = automatic; options.SystemClock = clock; }, SignInAsAlice); var url = "http://example.com/forbid"; var transaction = await SendAsync(server, url); transaction.Response.StatusCode.ShouldBe(HttpStatusCode.Redirect); var location = transaction.Response.Headers.Location; location.LocalPath.ShouldBe("/Account/AccessDenied"); }
public void NegativeRelativeExpirationThrows() { var clock = new TestClock(); var cache = CreateCache(clock); var key = "myKey"; var value = new object(); ExceptionAssert.ThrowsArgumentOutOfRange(() => { var result = cache.Set(key, value, new MemoryCacheEntryOptions() .SetAbsoluteExpiration(TimeSpan.FromMinutes(-1))); }, nameof(MemoryCacheEntryOptions.AbsoluteExpirationRelativeToNow), "The relative expiration value must be positive.", TimeSpan.FromMinutes(-1)); }
public async Task CookieContainsIdentity() { var clock = new TestClock(); var server = CreateServer(options => { options.SystemClock = clock; }, SignInAsAlice); var transaction1 = await SendAsync(server, "http://example.com/testpath"); var transaction2 = await SendAsync(server, "http://example.com/me/Cookies", transaction1.CookieNameValue); FindClaimValue(transaction2, ClaimTypes.Name).ShouldBe("Alice"); }