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);
        }
Example #5
0
        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);
        }
Example #16
0
        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");
        }
Example #19
0
        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");
        }