This commit is contained in:
parent
1189a2c294
commit
1ba180e87c
|
|
@ -24,10 +24,6 @@ namespace Microsoft.Net.Http.Headers
|
||||||
private static readonly string SameSiteLaxToken = SameSiteMode.Lax.ToString().ToLower();
|
private static readonly string SameSiteLaxToken = SameSiteMode.Lax.ToString().ToLower();
|
||||||
private static readonly string SameSiteStrictToken = SameSiteMode.Strict.ToString().ToLower();
|
private static readonly string SameSiteStrictToken = SameSiteMode.Strict.ToString().ToLower();
|
||||||
|
|
||||||
// True (old): https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-3.1
|
|
||||||
// False (new): https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.1
|
|
||||||
internal static bool SuppressSameSiteNone;
|
|
||||||
|
|
||||||
private const string HttpOnlyToken = "httponly";
|
private const string HttpOnlyToken = "httponly";
|
||||||
private const string SeparatorToken = "; ";
|
private const string SeparatorToken = "; ";
|
||||||
private const string EqualsToken = "=";
|
private const string EqualsToken = "=";
|
||||||
|
|
@ -42,14 +38,6 @@ namespace Microsoft.Net.Http.Headers
|
||||||
private StringSegment _name;
|
private StringSegment _name;
|
||||||
private StringSegment _value;
|
private StringSegment _value;
|
||||||
|
|
||||||
static SetCookieHeaderValue()
|
|
||||||
{
|
|
||||||
if (AppContext.TryGetSwitch("Microsoft.AspNetCore.SuppressSameSiteNone", out var enabled))
|
|
||||||
{
|
|
||||||
SuppressSameSiteNone = enabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private SetCookieHeaderValue()
|
private SetCookieHeaderValue()
|
||||||
{
|
{
|
||||||
// Used by the parser to create a new instance of this type.
|
// Used by the parser to create a new instance of this type.
|
||||||
|
|
@ -106,7 +94,7 @@ namespace Microsoft.Net.Http.Headers
|
||||||
|
|
||||||
public bool Secure { get; set; }
|
public bool Secure { get; set; }
|
||||||
|
|
||||||
public SameSiteMode SameSite { get; set; } = SuppressSameSiteNone ? SameSiteMode.None : SameSiteMode.Unspecified;
|
public SameSiteMode SameSite { get; set; } = SameSiteMode.Unspecified;
|
||||||
|
|
||||||
public bool HttpOnly { get; set; }
|
public bool HttpOnly { get; set; }
|
||||||
|
|
||||||
|
|
@ -145,7 +133,7 @@ namespace Microsoft.Net.Http.Headers
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow for Unspecified (-1) to skip SameSite
|
// Allow for Unspecified (-1) to skip SameSite
|
||||||
if (SameSite == SameSiteMode.None && !SuppressSameSiteNone)
|
if (SameSite == SameSiteMode.None)
|
||||||
{
|
{
|
||||||
sameSite = SameSiteNoneToken;
|
sameSite = SameSiteNoneToken;
|
||||||
length += SeparatorToken.Length + SameSiteToken.Length + EqualsToken.Length + sameSite.Length;
|
length += SeparatorToken.Length + SameSiteToken.Length + EqualsToken.Length + sameSite.Length;
|
||||||
|
|
@ -275,7 +263,7 @@ namespace Microsoft.Net.Http.Headers
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow for Unspecified (-1) to skip SameSite
|
// Allow for Unspecified (-1) to skip SameSite
|
||||||
if (SameSite == SameSiteMode.None && !SuppressSameSiteNone)
|
if (SameSite == SameSiteMode.None)
|
||||||
{
|
{
|
||||||
AppendSegment(builder, SameSiteToken, SameSiteNoneToken);
|
AppendSegment(builder, SameSiteToken, SameSiteNoneToken);
|
||||||
}
|
}
|
||||||
|
|
@ -478,7 +466,7 @@ namespace Microsoft.Net.Http.Headers
|
||||||
{
|
{
|
||||||
if (!ReadEqualsSign(input, ref offset))
|
if (!ReadEqualsSign(input, ref offset))
|
||||||
{
|
{
|
||||||
result.SameSite = SuppressSameSiteNone ? SameSiteMode.Strict : SameSiteMode.Unspecified;
|
result.SameSite = SameSiteMode.Unspecified;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -492,14 +480,13 @@ namespace Microsoft.Net.Http.Headers
|
||||||
{
|
{
|
||||||
result.SameSite = SameSiteMode.Lax;
|
result.SameSite = SameSiteMode.Lax;
|
||||||
}
|
}
|
||||||
else if (!SuppressSameSiteNone
|
else if (StringSegment.Equals(enforcementMode, SameSiteNoneToken, StringComparison.OrdinalIgnoreCase))
|
||||||
&& StringSegment.Equals(enforcementMode, SameSiteNoneToken, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
result.SameSite = SameSiteMode.None;
|
result.SameSite = SameSiteMode.None;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
result.SameSite = SuppressSameSiteNone ? SameSiteMode.Strict : SameSiteMode.Unspecified;
|
result.SameSite = SameSiteMode.Unspecified;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -313,28 +313,6 @@ namespace Microsoft.Net.Http.Headers
|
||||||
Assert.Equal(expectedValue, input.ToString());
|
Assert.Equal(expectedValue, input.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void SetCookieHeaderValue_ToString_SameSiteNoneCompat()
|
|
||||||
{
|
|
||||||
SetCookieHeaderValue.SuppressSameSiteNone = true;
|
|
||||||
|
|
||||||
var input = new SetCookieHeaderValue("name", "value")
|
|
||||||
{
|
|
||||||
SameSite = SameSiteMode.None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Assert.Equal("name=value", input.ToString());
|
|
||||||
|
|
||||||
SetCookieHeaderValue.SuppressSameSiteNone = false;
|
|
||||||
|
|
||||||
var input2 = new SetCookieHeaderValue("name", "value")
|
|
||||||
{
|
|
||||||
SameSite = SameSiteMode.None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Assert.Equal("name=value; samesite=none", input2.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(SetCookieHeaderDataSet))]
|
[MemberData(nameof(SetCookieHeaderDataSet))]
|
||||||
public void SetCookieHeaderValue_AppendToStringBuilder(SetCookieHeaderValue input, string expectedValue)
|
public void SetCookieHeaderValue_AppendToStringBuilder(SetCookieHeaderValue input, string expectedValue)
|
||||||
|
|
@ -346,32 +324,6 @@ namespace Microsoft.Net.Http.Headers
|
||||||
Assert.Equal(expectedValue, builder.ToString());
|
Assert.Equal(expectedValue, builder.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void SetCookieHeaderValue_AppendToStringBuilder_SameSiteNoneCompat()
|
|
||||||
{
|
|
||||||
SetCookieHeaderValue.SuppressSameSiteNone = true;
|
|
||||||
|
|
||||||
var builder = new StringBuilder();
|
|
||||||
var input = new SetCookieHeaderValue("name", "value")
|
|
||||||
{
|
|
||||||
SameSite = SameSiteMode.None,
|
|
||||||
};
|
|
||||||
|
|
||||||
input.AppendToStringBuilder(builder);
|
|
||||||
Assert.Equal("name=value", builder.ToString());
|
|
||||||
|
|
||||||
SetCookieHeaderValue.SuppressSameSiteNone = false;
|
|
||||||
|
|
||||||
var builder2 = new StringBuilder();
|
|
||||||
var input2 = new SetCookieHeaderValue("name", "value")
|
|
||||||
{
|
|
||||||
SameSite = SameSiteMode.None,
|
|
||||||
};
|
|
||||||
|
|
||||||
input2.AppendToStringBuilder(builder2);
|
|
||||||
Assert.Equal("name=value; samesite=none", builder2.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(SetCookieHeaderDataSet))]
|
[MemberData(nameof(SetCookieHeaderDataSet))]
|
||||||
public void SetCookieHeaderValue_Parse_AcceptsValidValues(SetCookieHeaderValue cookie, string expectedValue)
|
public void SetCookieHeaderValue_Parse_AcceptsValidValues(SetCookieHeaderValue cookie, string expectedValue)
|
||||||
|
|
@ -382,31 +334,6 @@ namespace Microsoft.Net.Http.Headers
|
||||||
Assert.Equal(expectedValue, header.ToString());
|
Assert.Equal(expectedValue, header.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void SetCookieHeaderValue_Parse_AcceptsValidValues_SameSiteNoneCompat()
|
|
||||||
{
|
|
||||||
SetCookieHeaderValue.SuppressSameSiteNone = true;
|
|
||||||
var header = SetCookieHeaderValue.Parse("name=value; samesite=none");
|
|
||||||
|
|
||||||
var cookie = new SetCookieHeaderValue("name", "value")
|
|
||||||
{
|
|
||||||
SameSite = SameSiteMode.Strict,
|
|
||||||
};
|
|
||||||
|
|
||||||
Assert.Equal(cookie, header);
|
|
||||||
Assert.Equal("name=value; samesite=strict", header.ToString());
|
|
||||||
SetCookieHeaderValue.SuppressSameSiteNone = false;
|
|
||||||
|
|
||||||
var header2 = SetCookieHeaderValue.Parse("name=value; samesite=none");
|
|
||||||
|
|
||||||
var cookie2 = new SetCookieHeaderValue("name", "value")
|
|
||||||
{
|
|
||||||
SameSite = SameSiteMode.None,
|
|
||||||
};
|
|
||||||
Assert.Equal(cookie2, header2);
|
|
||||||
Assert.Equal("name=value; samesite=none", header2.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(SetCookieHeaderDataSet))]
|
[MemberData(nameof(SetCookieHeaderDataSet))]
|
||||||
public void SetCookieHeaderValue_TryParse_AcceptsValidValues(SetCookieHeaderValue cookie, string expectedValue)
|
public void SetCookieHeaderValue_TryParse_AcceptsValidValues(SetCookieHeaderValue cookie, string expectedValue)
|
||||||
|
|
@ -417,31 +344,6 @@ namespace Microsoft.Net.Http.Headers
|
||||||
Assert.Equal(expectedValue, header.ToString());
|
Assert.Equal(expectedValue, header.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void SetCookieHeaderValue_TryParse_AcceptsValidValues_SameSiteNoneCompat()
|
|
||||||
{
|
|
||||||
SetCookieHeaderValue.SuppressSameSiteNone = true;
|
|
||||||
Assert.True(SetCookieHeaderValue.TryParse("name=value; samesite=none", out var header));
|
|
||||||
var cookie = new SetCookieHeaderValue("name", "value")
|
|
||||||
{
|
|
||||||
SameSite = SameSiteMode.Strict,
|
|
||||||
};
|
|
||||||
|
|
||||||
Assert.Equal(cookie, header);
|
|
||||||
Assert.Equal("name=value; samesite=strict", header.ToString());
|
|
||||||
|
|
||||||
SetCookieHeaderValue.SuppressSameSiteNone = false;
|
|
||||||
|
|
||||||
Assert.True(SetCookieHeaderValue.TryParse("name=value; samesite=none", out var header2));
|
|
||||||
var cookie2 = new SetCookieHeaderValue("name", "value")
|
|
||||||
{
|
|
||||||
SameSite = SameSiteMode.None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Assert.Equal(cookie2, header2);
|
|
||||||
Assert.Equal("name=value; samesite=none", header2.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[MemberData(nameof(InvalidSetCookieHeaderDataSet))]
|
[MemberData(nameof(InvalidSetCookieHeaderDataSet))]
|
||||||
public void SetCookieHeaderValue_Parse_RejectsInvalidValues(string value)
|
public void SetCookieHeaderValue_Parse_RejectsInvalidValues(string value)
|
||||||
|
|
|
||||||
|
|
@ -11,20 +11,8 @@ namespace Microsoft.AspNetCore.Http
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CookieBuilder
|
public class CookieBuilder
|
||||||
{
|
{
|
||||||
// True (old): https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-3.1
|
|
||||||
// False (new): https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.1
|
|
||||||
internal static bool SuppressSameSiteNone;
|
|
||||||
|
|
||||||
private string _name;
|
private string _name;
|
||||||
|
|
||||||
static CookieBuilder()
|
|
||||||
{
|
|
||||||
if (AppContext.TryGetSwitch("Microsoft.AspNetCore.SuppressSameSiteNone", out var enabled))
|
|
||||||
{
|
|
||||||
SuppressSameSiteNone = enabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The name of the cookie.
|
/// The name of the cookie.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -66,7 +54,7 @@ namespace Microsoft.AspNetCore.Http
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// Determines the value that will set on <seealso cref="CookieOptions.SameSite"/>.
|
/// Determines the value that will set on <seealso cref="CookieOptions.SameSite"/>.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public virtual SameSiteMode SameSite { get; set; } = SuppressSameSiteNone ? SameSiteMode.None : SameSiteMode.Unspecified;
|
public virtual SameSiteMode SameSite { get; set; } = SameSiteMode.Unspecified;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The policy that will be used to determine <seealso cref="CookieOptions.Secure"/>.
|
/// The policy that will be used to determine <seealso cref="CookieOptions.Secure"/>.
|
||||||
|
|
|
||||||
|
|
@ -10,18 +10,6 @@ namespace Microsoft.AspNetCore.Http
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CookieOptions
|
public class CookieOptions
|
||||||
{
|
{
|
||||||
// True (old): https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-3.1
|
|
||||||
// False (new): https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.1
|
|
||||||
internal static bool SuppressSameSiteNone;
|
|
||||||
|
|
||||||
static CookieOptions()
|
|
||||||
{
|
|
||||||
if (AppContext.TryGetSwitch("Microsoft.AspNetCore.SuppressSameSiteNone", out var enabled))
|
|
||||||
{
|
|
||||||
SuppressSameSiteNone = enabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a default cookie with a path of '/'.
|
/// Creates a default cookie with a path of '/'.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -58,7 +46,7 @@ namespace Microsoft.AspNetCore.Http
|
||||||
/// Gets or sets the value for the SameSite attribute of the cookie. The default value is <see cref="SameSiteMode.Unspecified"/>
|
/// Gets or sets the value for the SameSite attribute of the cookie. The default value is <see cref="SameSiteMode.Unspecified"/>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The <see cref="SameSiteMode"/> representing the enforcement mode of the cookie.</returns>
|
/// <returns>The <see cref="SameSiteMode"/> representing the enforcement mode of the cookie.</returns>
|
||||||
public SameSiteMode SameSite { get; set; } = SuppressSameSiteNone ? SameSiteMode.None : SameSiteMode.Unspecified;
|
public SameSiteMode SameSite { get; set; } = SameSiteMode.Unspecified;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value that indicates whether a cookie is accessible by client-side script.
|
/// Gets or sets a value that indicates whether a cookie is accessible by client-side script.
|
||||||
|
|
|
||||||
|
|
@ -12,22 +12,10 @@ namespace Microsoft.AspNetCore.Builder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CookiePolicyOptions
|
public class CookiePolicyOptions
|
||||||
{
|
{
|
||||||
// True (old): https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-3.1
|
|
||||||
// False (new): https://tools.ietf.org/html/draft-ietf-httpbis-rfc6265bis-03#section-4.1.1
|
|
||||||
internal static bool SuppressSameSiteNone;
|
|
||||||
|
|
||||||
static CookiePolicyOptions()
|
|
||||||
{
|
|
||||||
if (AppContext.TryGetSwitch("Microsoft.AspNetCore.SuppressSameSiteNone", out var enabled))
|
|
||||||
{
|
|
||||||
SuppressSameSiteNone = enabled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Affects the cookie's same site attribute.
|
/// Affects the cookie's same site attribute.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SameSiteMode MinimumSameSitePolicy { get; set; } = SuppressSameSiteNone ? SameSiteMode.None : SameSiteMode.Unspecified;
|
public SameSiteMode MinimumSameSitePolicy { get; set; } = SameSiteMode.Unspecified;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Affects whether cookies must be HttpOnly.
|
/// Affects whether cookies must be HttpOnly.
|
||||||
|
|
|
||||||
|
|
@ -115,8 +115,7 @@ namespace Microsoft.AspNetCore.CookiePolicy
|
||||||
private bool CheckPolicyRequired()
|
private bool CheckPolicyRequired()
|
||||||
{
|
{
|
||||||
return !CanTrack
|
return !CanTrack
|
||||||
|| (CookiePolicyOptions.SuppressSameSiteNone && Options.MinimumSameSitePolicy != SameSiteMode.None)
|
|| Options.MinimumSameSitePolicy != SameSiteMode.Unspecified
|
||||||
|| (!CookiePolicyOptions.SuppressSameSiteNone && Options.MinimumSameSitePolicy != SameSiteMode.Unspecified)
|
|
||||||
|| Options.HttpOnly != HttpOnlyPolicy.None
|
|| Options.HttpOnly != HttpOnlyPolicy.None
|
||||||
|| Options.Secure != CookieSecurePolicy.None;
|
|| Options.Secure != CookieSecurePolicy.None;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue