diff --git a/src/Microsoft.AspNetCore.Session/SessionMiddleware.cs b/src/Microsoft.AspNetCore.Session/SessionMiddleware.cs
index 8f6ff45..23386f2 100644
--- a/src/Microsoft.AspNetCore.Session/SessionMiddleware.cs
+++ b/src/Microsoft.AspNetCore.Session/SessionMiddleware.cs
@@ -156,7 +156,15 @@ private void SetCookie()
HttpOnly = _options.CookieHttpOnly,
Path = _options.CookiePath ?? SessionDefaults.CookiePath,
};
-
+ if (_options.CookieSecure == CookieSecurePolicy.SameAsRequest)
+ {
+ cookieOptions.Secure = _context.Request.IsHttps;
+ }
+ else
+ {
+ cookieOptions.Secure = _options.CookieSecure == CookieSecurePolicy.Always;
+ }
+
_context.Response.Cookies.Append(_options.CookieName, _cookieValue, cookieOptions);
_context.Response.Headers["Cache-Control"] = "no-cache";
diff --git a/src/Microsoft.AspNetCore.Session/SessionOptions.cs b/src/Microsoft.AspNetCore.Session/SessionOptions.cs
index 12caa67..7240ece 100644
--- a/src/Microsoft.AspNetCore.Session/SessionOptions.cs
+++ b/src/Microsoft.AspNetCore.Session/SessionOptions.cs
@@ -3,6 +3,7 @@
using System;
using Microsoft.AspNetCore.Session;
+using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Builder
{
@@ -35,6 +36,13 @@ public class SessionOptions
///
public bool CookieHttpOnly { get; set; } = true;
+ ///
+ /// Determines if the cookie should only be transmitted on HTTPS request. The default is to limit the cookie
+ /// to HTTPS requests if the page which is doing the SignIn is also HTTPS. If you have an HTTPS sign in page
+ /// and portions of your site are HTTP you may need to change this value.
+ ///
+ public CookieSecurePolicy CookieSecure { get; set; }
+
///
/// The IdleTimeout indicates how long the session can be idle before its contents are abandoned. Each session access
/// resets the timeout. Note this only applies to the content of the session, not the cookie.
diff --git a/test/Microsoft.AspNetCore.Session.Tests/SessionTests.cs b/test/Microsoft.AspNetCore.Session.Tests/SessionTests.cs
index 7c81e78..f061f28 100644
--- a/test/Microsoft.AspNetCore.Session.Tests/SessionTests.cs
+++ b/test/Microsoft.AspNetCore.Session.Tests/SessionTests.cs
@@ -87,6 +87,58 @@ public async Task SettingAValueCausesTheCookieToBeCreated()
}
}
+ [Theory]
+ [InlineData(CookieSecurePolicy.Always, "http://example.com/testpath", true)]
+ [InlineData(CookieSecurePolicy.Always, "https://example.com/testpath", true)]
+ [InlineData(CookieSecurePolicy.None, "http://example.com/testpath", false)]
+ [InlineData(CookieSecurePolicy.None, "https://example.com/testpath", false)]
+ [InlineData(CookieSecurePolicy.SameAsRequest, "http://example.com/testpath", false)]
+ [InlineData(CookieSecurePolicy.SameAsRequest, "https://example.com/testpath", true)]
+ public async Task SecureSignInCausesSecureOnlyCookieByDefault(
+ CookieSecurePolicy cookieSecurePolicy,
+ string requestUri,
+ bool shouldBeSecureOnly)
+ {
+ var builder = new WebHostBuilder()
+ .Configure(app =>
+ {
+ app.UseSession(new SessionOptions
+ {
+ CookieName = "TestCookie",
+ CookieSecure = cookieSecurePolicy
+ });
+ app.Run(context =>
+ {
+ Assert.Null(context.Session.GetString("Key"));
+ context.Session.SetString("Key", "Value");
+ Assert.Equal("Value", context.Session.GetString("Key"));
+ return Task.FromResult(0);
+ });
+ })
+ .ConfigureServices(services =>
+ {
+ services.AddDistributedMemoryCache();
+ services.AddSession();
+ });
+ using (var server = new TestServer(builder))
+ {
+ var client = server.CreateClient();
+ var response = await client.GetAsync(requestUri);
+ response.EnsureSuccessStatusCode();
+ IEnumerable values;
+ Assert.True(response.Headers.TryGetValues("Set-Cookie", out values));
+ Assert.Equal(1, values.Count());
+ if (shouldBeSecureOnly)
+ {
+ Assert.Contains("; secure", values.First());
+ }
+ else
+ {
+ Assert.DoesNotContain("; secure", values.First());
+ }
+ }
+ }
+
[Fact]
public async Task SessionCanBeAccessedOnTheNextRequest()
{