Marked CookieTempDataProvider's cookie as non-essential
[Fixes #7160] Determine if the temp data cookie is considered essential
This commit is contained in:
parent
1fa1d7df3e
commit
9fd60ff864
|
|
@ -12,6 +12,7 @@
|
||||||
<MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>2.1.0-preview1-27965</MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>
|
<MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>2.1.0-preview1-27965</MicrosoftAspNetCoreAuthorizationPolicyPackageVersion>
|
||||||
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.0-preview1-27965</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
|
<MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>2.1.0-preview1-27965</MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion>
|
||||||
<MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>2.1.0-preview1-27965</MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>
|
<MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>2.1.0-preview1-27965</MicrosoftAspNetCoreChunkingCookieManagerSourcesPackageVersion>
|
||||||
|
<MicrosoftAspNetCoreCookiePolicyPackageVersion>2.1.0-preview1-27965</MicrosoftAspNetCoreCookiePolicyPackageVersion>
|
||||||
<MicrosoftAspNetCoreCorsPackageVersion>2.1.0-preview1-27965</MicrosoftAspNetCoreCorsPackageVersion>
|
<MicrosoftAspNetCoreCorsPackageVersion>2.1.0-preview1-27965</MicrosoftAspNetCoreCorsPackageVersion>
|
||||||
<MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>2.1.0-preview1-27965</MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>
|
<MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>2.1.0-preview1-27965</MicrosoftAspNetCoreDiagnosticsAbstractionsPackageVersion>
|
||||||
<MicrosoftAspNetCoreDiagnosticsPackageVersion>2.1.0-preview1-27965</MicrosoftAspNetCoreDiagnosticsPackageVersion>
|
<MicrosoftAspNetCoreDiagnosticsPackageVersion>2.1.0-preview1-27965</MicrosoftAspNetCoreDiagnosticsPackageVersion>
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,11 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
HttpOnly = true,
|
HttpOnly = true,
|
||||||
SameSite = SameSiteMode.Strict,
|
SameSite = SameSiteMode.Strict,
|
||||||
|
|
||||||
|
// This cookie has been marked as non-essential because a user could use the SessionStateTempDataProvider,
|
||||||
|
// which is more common in production scenarios. Check the comment on CookieBuilder below
|
||||||
|
// for more information.
|
||||||
|
IsEssential = false,
|
||||||
|
|
||||||
// Some browsers do not allow non-secure endpoints to set cookies with a 'secure' flag or overwrite cookies
|
// Some browsers do not allow non-secure endpoints to set cookies with a 'secure' flag or overwrite cookies
|
||||||
// whose 'secure' flag is set (http://httpwg.org/http-extensions/draft-ietf-httpbis-cookie-alone.html).
|
// whose 'secure' flag is set (http://httpwg.org/http-extensions/draft-ietf-httpbis-cookie-alone.html).
|
||||||
// Since mixing secure and non-secure endpoints is a common scenario in applications, we are relaxing the
|
// Since mixing secure and non-secure endpoints is a common scenario in applications, we are relaxing the
|
||||||
|
|
@ -33,7 +38,11 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
/// <para>
|
/// <para>
|
||||||
/// <see cref="CookieBuilder.SameSite"/> defaults to <see cref="SameSiteMode.Strict"/>.
|
/// <see cref="CookieBuilder.SameSite"/> defaults to <see cref="SameSiteMode.Strict"/>.
|
||||||
/// <see cref="CookieBuilder.SecurePolicy"/> defaults to <see cref="CookieSecurePolicy.SameAsRequest" />.
|
/// <see cref="CookieBuilder.SecurePolicy"/> defaults to <see cref="CookieSecurePolicy.SameAsRequest" />.
|
||||||
/// <see cref="CookieBuilder.HttpOnly"/> defaults to <c>true</c>
|
/// <see cref="CookieBuilder.HttpOnly"/> defaults to <c>true</c>.
|
||||||
|
/// <see cref="CookieBuilder.IsEssential"/> defaults to <c>false</c>, This property is only considered when a
|
||||||
|
/// user opts into the CookiePolicyMiddleware. If you are using this middleware and want to use
|
||||||
|
/// <see cref="CookieTempDataProvider"/>, then either set this property to <c>true</c> or
|
||||||
|
/// request user consent for non-essential cookies.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CookieBuilder Cookie
|
public CookieBuilder Cookie
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Net.Http.Headers;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
|
{
|
||||||
|
public class TempDataInCookiesUsingCookieConsentTest
|
||||||
|
: IClassFixture<MvcTestFixture<BasicWebSite.StartupWithCookieTempDataProviderAndCookieConsent>>
|
||||||
|
{
|
||||||
|
private readonly HttpClient _client;
|
||||||
|
|
||||||
|
public TempDataInCookiesUsingCookieConsentTest(
|
||||||
|
MvcTestFixture<BasicWebSite.StartupWithCookieTempDataProviderAndCookieConsent> fixture)
|
||||||
|
{
|
||||||
|
_client = fixture.Client;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CookieTempDataProviderCookie_SetInResponse_OnGrantingConsent()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var nameValueCollection = new List<KeyValuePair<string, string>>
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, string>("value", "Foo"),
|
||||||
|
};
|
||||||
|
var content = new FormUrlEncodedContent(nameValueCollection);
|
||||||
|
// This response would have the consent cookie which would be sent on rest of the requests here
|
||||||
|
var response = await _client.GetAsync("/TempData/GrantConsent");
|
||||||
|
|
||||||
|
// Act 1
|
||||||
|
response = await _client.SendAsync(GetPostRequest("/TempData/SetTempData", content, response));
|
||||||
|
|
||||||
|
// Assert 1
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
|
||||||
|
// Act 2
|
||||||
|
response = await _client.SendAsync(GetRequest("/TempData/GetTempData", response));
|
||||||
|
|
||||||
|
// Assert 2
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
var body = await response.Content.ReadAsStringAsync();
|
||||||
|
Assert.Equal("Foo", body);
|
||||||
|
|
||||||
|
// Act 3
|
||||||
|
response = await _client.SendAsync(GetRequest("/TempData/GetTempData", response));
|
||||||
|
|
||||||
|
// Assert 3
|
||||||
|
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task CookieTempDataProviderCookie_NotSetInResponse_OnNoConsent()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var nameValueCollection = new List<KeyValuePair<string, string>>
|
||||||
|
{
|
||||||
|
new KeyValuePair<string, string>("value", "Foo"),
|
||||||
|
};
|
||||||
|
var content = new FormUrlEncodedContent(nameValueCollection);
|
||||||
|
|
||||||
|
// Act 1
|
||||||
|
var response = await _client.PostAsync("/TempData/SetTempData", content);
|
||||||
|
|
||||||
|
// Assert 1
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
|
||||||
|
// Act 2
|
||||||
|
response = await _client.SendAsync(GetRequest("/TempData/GetTempData", response));
|
||||||
|
|
||||||
|
// Assert 2
|
||||||
|
Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpRequestMessage GetRequest(string path, HttpResponseMessage response)
|
||||||
|
{
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, path);
|
||||||
|
SetCookieHeaders(request, response);
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private HttpRequestMessage GetPostRequest(string path, HttpContent content, HttpResponseMessage response)
|
||||||
|
{
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Post, path);
|
||||||
|
request.Content = content;
|
||||||
|
SetCookieHeaders(request, response);
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetCookieHeaders(HttpRequestMessage request, HttpResponseMessage response)
|
||||||
|
{
|
||||||
|
IEnumerable<string> values;
|
||||||
|
if (response.Headers.TryGetValues("Set-Cookie", out values))
|
||||||
|
{
|
||||||
|
foreach (var cookie in SetCookieHeaderValue.ParseList(values.ToList()))
|
||||||
|
{
|
||||||
|
if (cookie.Expires == null || cookie.Expires >= DateTimeOffset.UtcNow)
|
||||||
|
{
|
||||||
|
request.Headers.Add("Cookie", new CookieHeaderValue(cookie.Name, cookie.Value).ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,5 +13,6 @@
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Session" Version="$(MicrosoftAspNetCoreSessionPackageVersion)" />
|
<PackageReference Include="Microsoft.AspNetCore.Session" Version="$(MicrosoftAspNetCoreSessionPackageVersion)" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="$(MicrosoftAspNetCoreStaticFilesPackageVersion)" />
|
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="$(MicrosoftAspNetCoreStaticFilesPackageVersion)" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(MicrosoftAspNetCoreDiagnosticsPackageVersion)" />
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics" Version="$(MicrosoftAspNetCoreDiagnosticsPackageVersion)" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.CookiePolicy" Version="$(MicrosoftAspNetCoreCookiePolicyPackageVersion)" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BasicWebSite.Filters;
|
using BasicWebSite.Filters;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace BasicWebSite.Controllers
|
namespace BasicWebSite.Controllers
|
||||||
|
|
@ -117,5 +118,11 @@ namespace BasicWebSite.Controllers
|
||||||
{
|
{
|
||||||
return TempData[nameof(UnhandledExceptionAndSettingTempData)]?.ToString();
|
return TempData[nameof(UnhandledExceptionAndSettingTempData)]?.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public void GrantConsent()
|
||||||
|
{
|
||||||
|
HttpContext.Features.Get<ITrackingConsentFeature>().GrantConsent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace BasicWebSite
|
||||||
|
{
|
||||||
|
public class StartupWithCookieTempDataProviderAndCookieConsent
|
||||||
|
{
|
||||||
|
public void ConfigureServices(IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddMvc();
|
||||||
|
|
||||||
|
services.Configure<CookiePolicyOptions>(o =>
|
||||||
|
{
|
||||||
|
o.CheckConsentNeeded = httpContext => true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Configure(IApplicationBuilder app)
|
||||||
|
{
|
||||||
|
app.UseDeveloperExceptionPage();
|
||||||
|
|
||||||
|
app.UseCookiePolicy();
|
||||||
|
|
||||||
|
app.UseMvcWithDefaultRoute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue