diff --git a/src/Microsoft.AspNetCore.Antiforgery/AntiforgeryOptions.cs b/src/Microsoft.AspNetCore.Antiforgery/AntiforgeryOptions.cs index 241edb8..f0de2da 100644 --- a/src/Microsoft.AspNetCore.Antiforgery/AntiforgeryOptions.cs +++ b/src/Microsoft.AspNetCore.Antiforgery/AntiforgeryOptions.cs @@ -14,102 +14,123 @@ public class AntiforgeryOptions private const string AntiforgeryTokenFieldName = "__RequestVerificationToken"; private const string AntiforgeryTokenHeaderName = "RequestVerificationToken"; - private string _cookieName; private string _formFieldName = AntiforgeryTokenFieldName; + private CookieBuilder _cookieBuilder = new CookieBuilder + { + SameSite = SameSiteMode.Strict, + HttpOnly = true + }; + /// /// The default cookie prefix, which is ".AspNetCore.Antiforgery.". /// public static readonly string DefaultCookiePrefix = ".AspNetCore.Antiforgery."; /// - /// Specifies the name of the cookie that is used by the antiforgery system. + /// Determines the settings used to create the antiforgery cookies. /// /// - /// If an explicit name is not provided, the system will automatically generate a + /// + /// If an explicit is not provided, the system will automatically generate a /// unique name that begins with . + /// + /// + /// defaults to . + /// defaults to true. + /// /// - public string CookieName + public CookieBuilder Cookie { - get - { - return _cookieName; - } - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - _cookieName = value; - } + get => _cookieBuilder; + set => _cookieBuilder = value ?? throw new ArgumentNullException(nameof(value)); } /// - /// This is obsolete and will be removed in a future version. - /// The recommended alternative is to use ConfigureCookieOptions. - /// The path set on the cookie. If set to null, the "path" attribute on the cookie is set to the current - /// request's value. If the value of is - /// null or empty, then the "path" attribute is set to the value of . + /// Specifies the name of the antiforgery token field that is used by the antiforgery system. /// - [Obsolete("This is obsolete and will be removed in a future version. The recommended alternative is to use ConfigureCookieOptions.")] - public PathString? CookiePath { get; set; } + public string FormFieldName + { + get => _formFieldName; + set => _formFieldName = value ?? throw new ArgumentNullException(nameof(value)); + } /// - /// This is obsolete and will be removed in a future version. - /// The recommended alternative is to use ConfigureCookieOptions. - /// The domain set on the cookie. By default its null which results in the "domain" attribute not being set. + /// Specifies the name of the header value that is used by the antiforgery system. If null then + /// antiforgery validation will only consider form data. /// - [Obsolete("This is obsolete and will be removed in a future version. The recommended alternative is to use ConfigureCookieOptions.")] - public string CookieDomain { get; set; } + public string HeaderName { get; set; } = AntiforgeryTokenHeaderName; /// - /// Configures the of the antiforgery cookies. Without additional configuration, the - /// default values antiforgery cookie options are true for , null for - /// and for . + /// Specifies whether to suppress the generation of X-Frame-Options header + /// which is used to prevent ClickJacking. By default, the X-Frame-Options + /// header is generated with the value SAMEORIGIN. If this setting is 'true', + /// the X-Frame-Options header will not be generated for the response. /// - public Action ConfigureCookieOptions { get; set; } + public bool SuppressXFrameOptionsHeader { get; set; } + #region Obsolete API /// - /// Specifies the name of the antiforgery token field that is used by the antiforgery system. + /// + /// This property is obsolete and will be removed in a future version. The recommended alternative is on . + /// + /// + /// Specifies the name of the cookie that is used by the antiforgery system. + /// /// - public string FormFieldName - { - get - { - return _formFieldName; - } - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } + /// + /// If an explicit name is not provided, the system will automatically generate a + /// unique name that begins with . + /// + [Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.Name) + ".")] + public string CookieName { get => Cookie.Name; set => Cookie.Name = value; } - _formFieldName = value; - } - } + /// + /// + /// This property is obsolete and will be removed in a future version. The recommended alternative is on . + /// + /// + /// The path set on the cookie. If set to null, the "path" attribute on the cookie is set to the current + /// request's value. If the value of is + /// null or empty, then the "path" attribute is set to the value of . + /// + /// + [Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.Path) + ".")] + public PathString? CookiePath { get => Cookie.Path; set => Cookie.Path = value; } /// - /// Specifies the name of the header value that is used by the antiforgery system. If null then - /// antiforgery validation will only consider form data. + /// + /// This property is obsolete and will be removed in a future version. The recommended alternative is on . + /// + /// + /// The domain set on the cookie. By default its null which results in the "domain" attribute not being set. + /// /// - public string HeaderName { get; set; } = AntiforgeryTokenHeaderName; + [Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is " + nameof(Cookie) + "." + nameof(CookieBuilder.Domain) + ".")] + public string CookieDomain { get => Cookie.Domain; set => Cookie.Domain = value; } + /// + /// + /// This property is obsolete and will be removed in a future version. + /// The recommended alternative is to set on . + /// + /// + /// true is equivalent to . + /// false is equivalent to . + /// + /// /// Specifies whether SSL is required for the antiforgery system /// to operate. If this setting is 'true' and a non-SSL request /// comes into the system, all antiforgery APIs will fail. + /// /// - public bool RequireSsl { get; set; } - - /// - /// Specifies whether to suppress the generation of X-Frame-Options header - /// which is used to prevent ClickJacking. By default, the X-Frame-Options - /// header is generated with the value SAMEORIGIN. If this setting is 'true', - /// the X-Frame-Options header will not be generated for the response. - /// - public bool SuppressXFrameOptionsHeader { get; set; } + [Obsolete("This property is obsolete and will be removed in a future version. The recommended alternative is to set " + nameof(Cookie) + "." + nameof(CookieBuilder.SecurePolicy) + ".")] + public bool RequireSsl + { + get => Cookie.SecurePolicy == CookieSecurePolicy.Always; + set => Cookie.SecurePolicy = value ? CookieSecurePolicy.Always : CookieSecurePolicy.None; + } + #endregion } -} \ No newline at end of file +} diff --git a/src/Microsoft.AspNetCore.Antiforgery/Internal/AntiforgeryOptionsSetup.cs b/src/Microsoft.AspNetCore.Antiforgery/Internal/AntiforgeryOptionsSetup.cs index f503c47..a6bc826 100644 --- a/src/Microsoft.AspNetCore.Antiforgery/Internal/AntiforgeryOptionsSetup.cs +++ b/src/Microsoft.AspNetCore.Antiforgery/Internal/AntiforgeryOptionsSetup.cs @@ -18,10 +18,10 @@ public AntiforgeryOptionsSetup(IOptions dataProtectionOpt public static void ConfigureOptions(AntiforgeryOptions options, DataProtectionOptions dataProtectionOptions) { - if (options.CookieName == null) + if (options.Cookie.Name == null) { var applicationId = dataProtectionOptions.ApplicationDiscriminator ?? string.Empty; - options.CookieName = AntiforgeryOptions.DefaultCookiePrefix + ComputeCookieName(applicationId); + options.Cookie.Name = AntiforgeryOptions.DefaultCookiePrefix + ComputeCookieName(applicationId); } } diff --git a/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgery.cs b/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgery.cs index 5f84933..ae28906 100644 --- a/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgery.cs +++ b/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgery.cs @@ -111,7 +111,7 @@ public async Task IsRequestValidAsync(HttpContext httpContext) var tokens = await _tokenStore.GetRequestTokensAsync(httpContext); if (tokens.CookieToken == null) { - _logger.MissingCookieToken(_options.CookieName); + _logger.MissingCookieToken(_options.Cookie.Name); return false; } @@ -160,7 +160,7 @@ public async Task ValidateRequestAsync(HttpContext httpContext) if (tokens.CookieToken == null) { throw new AntiforgeryValidationException( - Resources.FormatAntiforgery_CookieToken_MustBeProvided(_options.CookieName)); + Resources.FormatAntiforgery_CookieToken_MustBeProvided(_options.Cookie.Name)); } if (tokens.RequestToken == null) @@ -265,12 +265,11 @@ private void SaveCookieTokenAndHeader(HttpContext httpContext, string cookieToke private void CheckSSLConfig(HttpContext context) { - if (_options.RequireSsl && !context.Request.IsHttps) + if (_options.Cookie.SecurePolicy == CookieSecurePolicy.Always && !context.Request.IsHttps) { - throw new InvalidOperationException(Resources.FormatAntiforgeryWorker_RequireSSL( - nameof(AntiforgeryOptions), - nameof(AntiforgeryOptions.RequireSsl), - "true")); + throw new InvalidOperationException(Resources.FormatAntiforgery_RequiresSSL( + string.Join(".", nameof(AntiforgeryOptions), nameof(AntiforgeryOptions.Cookie), nameof(CookieBuilder.SecurePolicy)), + nameof(CookieSecurePolicy.Always))); } } diff --git a/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenStore.cs b/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenStore.cs index 2fd0d95..95e6d6f 100644 --- a/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenStore.cs +++ b/src/Microsoft.AspNetCore.Antiforgery/Internal/DefaultAntiforgeryTokenStore.cs @@ -28,7 +28,7 @@ public string GetCookieToken(HttpContext httpContext) { Debug.Assert(httpContext != null); - var requestCookie = httpContext.Request.Cookies[_options.CookieName]; + var requestCookie = httpContext.Request.Cookies[_options.Cookie.Name]; if (string.IsNullOrEmpty(requestCookie)) { // unable to find the cookie. @@ -42,7 +42,7 @@ public async Task GetRequestTokensAsync(HttpContext httpCon { Debug.Assert(httpContext != null); - var cookieToken = httpContext.Request.Cookies[_options.CookieName]; + var cookieToken = httpContext.Request.Cookies[_options.Cookie.Name]; // We want to delay reading the form as much as possible, for example in case of large file uploads, // request token could be part of the header. @@ -69,22 +69,12 @@ public void SaveCookieToken(HttpContext httpContext, string token) Debug.Assert(httpContext != null); Debug.Assert(token != null); - var options = new CookieOptions - { - HttpOnly = true, -#pragma warning disable 618 - Domain = _options.CookieDomain, -#pragma warning restore 618 - SameSite = SameSiteMode.Strict, - Secure = _options.RequireSsl - }; - -#pragma warning disable 618 - if (_options.CookiePath != null) + var options = _options.Cookie.Build(httpContext); + + if (_options.Cookie.Path != null) { - options.Path = _options.CookiePath.ToString(); + options.Path = _options.Cookie.Path.ToString(); } -#pragma warning restore 618 else { var pathBase = httpContext.Request.PathBase.ToString(); @@ -94,9 +84,7 @@ public void SaveCookieToken(HttpContext httpContext, string token) } } - _options.ConfigureCookieOptions?.Invoke(httpContext, options); - - httpContext.Response.Cookies.Append(_options.CookieName, token, options); + httpContext.Response.Cookies.Append(_options.Cookie.Name, token, options); } } } diff --git a/src/Microsoft.AspNetCore.Antiforgery/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Antiforgery/Properties/Resources.Designer.cs index 6b12221..83811ea 100644 --- a/src/Microsoft.AspNetCore.Antiforgery/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Antiforgery/Properties/Resources.Designer.cs @@ -15,248 +15,224 @@ private static readonly ResourceManager _resourceManager /// internal static string AntiforgeryTokenValidator_AuthenticatedUserWithoutUsername { - get { return GetString("AntiforgeryTokenValidator_AuthenticatedUserWithoutUsername"); } + get => GetString("AntiforgeryTokenValidator_AuthenticatedUserWithoutUsername"); } /// /// The provided identity of type '{0}' is marked {1} = {2} but does not have a value for {3}. By default, the antiforgery system requires that all authenticated identities have a unique {3}. If it is not possible to provide a unique {3} for this identity, consider extending {4} by overriding the {5} or a custom type that can provide some form of unique identifier for the current user. /// internal static string FormatAntiforgeryTokenValidator_AuthenticatedUserWithoutUsername(object p0, object p1, object p2, object p3, object p4, object p5) - { - return string.Format(CultureInfo.CurrentCulture, GetString("AntiforgeryTokenValidator_AuthenticatedUserWithoutUsername"), p0, p1, p2, p3, p4, p5); - } + => string.Format(CultureInfo.CurrentCulture, GetString("AntiforgeryTokenValidator_AuthenticatedUserWithoutUsername"), p0, p1, p2, p3, p4, p5); /// /// The provided antiforgery token failed a custom data check. /// internal static string AntiforgeryToken_AdditionalDataCheckFailed { - get { return GetString("AntiforgeryToken_AdditionalDataCheckFailed"); } + get => GetString("AntiforgeryToken_AdditionalDataCheckFailed"); } /// /// The provided antiforgery token failed a custom data check. /// internal static string FormatAntiforgeryToken_AdditionalDataCheckFailed() - { - return GetString("AntiforgeryToken_AdditionalDataCheckFailed"); - } + => GetString("AntiforgeryToken_AdditionalDataCheckFailed"); /// /// The provided antiforgery token was meant for a different claims-based user than the current user. /// internal static string AntiforgeryToken_ClaimUidMismatch { - get { return GetString("AntiforgeryToken_ClaimUidMismatch"); } + get => GetString("AntiforgeryToken_ClaimUidMismatch"); } /// /// The provided antiforgery token was meant for a different claims-based user than the current user. /// internal static string FormatAntiforgeryToken_ClaimUidMismatch() - { - return GetString("AntiforgeryToken_ClaimUidMismatch"); - } + => GetString("AntiforgeryToken_ClaimUidMismatch"); /// /// The antiforgery token could not be decrypted. /// internal static string AntiforgeryToken_DeserializationFailed { - get { return GetString("AntiforgeryToken_DeserializationFailed"); } + get => GetString("AntiforgeryToken_DeserializationFailed"); } /// /// The antiforgery token could not be decrypted. /// internal static string FormatAntiforgeryToken_DeserializationFailed() - { - return GetString("AntiforgeryToken_DeserializationFailed"); - } + => GetString("AntiforgeryToken_DeserializationFailed"); /// /// The antiforgery cookie token and request token do not match. /// internal static string AntiforgeryToken_SecurityTokenMismatch { - get { return GetString("AntiforgeryToken_SecurityTokenMismatch"); } + get => GetString("AntiforgeryToken_SecurityTokenMismatch"); } /// /// The antiforgery cookie token and request token do not match. /// internal static string FormatAntiforgeryToken_SecurityTokenMismatch() - { - return GetString("AntiforgeryToken_SecurityTokenMismatch"); - } + => GetString("AntiforgeryToken_SecurityTokenMismatch"); /// /// Validation of the provided antiforgery token failed. The cookie token and the request token were swapped. /// internal static string AntiforgeryToken_TokensSwapped { - get { return GetString("AntiforgeryToken_TokensSwapped"); } + get => GetString("AntiforgeryToken_TokensSwapped"); } /// /// Validation of the provided antiforgery token failed. The cookie token and the request token were swapped. /// internal static string FormatAntiforgeryToken_TokensSwapped() - { - return GetString("AntiforgeryToken_TokensSwapped"); - } + => GetString("AntiforgeryToken_TokensSwapped"); /// /// The provided antiforgery token was meant for user "{0}", but the current user is "{1}". /// internal static string AntiforgeryToken_UsernameMismatch { - get { return GetString("AntiforgeryToken_UsernameMismatch"); } + get => GetString("AntiforgeryToken_UsernameMismatch"); } /// /// The provided antiforgery token was meant for user "{0}", but the current user is "{1}". /// internal static string FormatAntiforgeryToken_UsernameMismatch(object p0, object p1) - { - return string.Format(CultureInfo.CurrentCulture, GetString("AntiforgeryToken_UsernameMismatch"), p0, p1); - } - - /// - /// The antiforgery system has the configuration value {0}.{1} = {2}, but the current request is not an SSL request. - /// - internal static string AntiforgeryWorker_RequireSSL - { - get { return GetString("AntiforgeryWorker_RequireSSL"); } - } + => string.Format(CultureInfo.CurrentCulture, GetString("AntiforgeryToken_UsernameMismatch"), p0, p1); /// - /// The antiforgery system has the configuration value {0}.{1} = {2}, but the current request is not an SSL request. + /// The antiforgery cookie token is invalid. /// - internal static string FormatAntiforgeryWorker_RequireSSL(object p0, object p1, object p2) + internal static string Antiforgery_CookieToken_IsInvalid { - return string.Format(CultureInfo.CurrentCulture, GetString("AntiforgeryWorker_RequireSSL"), p0, p1, p2); + get => GetString("Antiforgery_CookieToken_IsInvalid"); } /// - /// The required antiforgery cookie "{0}" is not present. + /// The antiforgery cookie token is invalid. /// - internal static string Antiforgery_CookieToken_IsInvalid - { - get { return GetString("Antiforgery_CookieToken_IsInvalid"); } - } + internal static string FormatAntiforgery_CookieToken_IsInvalid() + => GetString("Antiforgery_CookieToken_IsInvalid"); /// /// The required antiforgery cookie "{0}" is not present. /// internal static string Antiforgery_CookieToken_MustBeProvided { - get { return GetString("Antiforgery_CookieToken_MustBeProvided"); } + get => GetString("Antiforgery_CookieToken_MustBeProvided"); } /// /// The required antiforgery cookie "{0}" is not present. /// internal static string FormatAntiforgery_CookieToken_MustBeProvided(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("Antiforgery_CookieToken_MustBeProvided"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("Antiforgery_CookieToken_MustBeProvided"), p0); /// /// The required antiforgery cookie token must be provided. /// internal static string Antiforgery_CookieToken_MustBeProvided_Generic { - get { return GetString("Antiforgery_CookieToken_MustBeProvided_Generic"); } + get => GetString("Antiforgery_CookieToken_MustBeProvided_Generic"); } /// /// The required antiforgery cookie token must be provided. /// internal static string FormatAntiforgery_CookieToken_MustBeProvided_Generic() - { - return GetString("Antiforgery_CookieToken_MustBeProvided_Generic"); - } + => GetString("Antiforgery_CookieToken_MustBeProvided_Generic"); /// /// The required antiforgery form field "{0}" is not present. /// internal static string Antiforgery_FormToken_MustBeProvided { - get { return GetString("Antiforgery_FormToken_MustBeProvided"); } + get => GetString("Antiforgery_FormToken_MustBeProvided"); } /// /// The required antiforgery form field "{0}" is not present. /// internal static string FormatAntiforgery_FormToken_MustBeProvided(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("Antiforgery_FormToken_MustBeProvided"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("Antiforgery_FormToken_MustBeProvided"), p0); /// /// The required antiforgery header value "{0}" is not present. /// internal static string Antiforgery_HeaderToken_MustBeProvided { - get { return GetString("Antiforgery_HeaderToken_MustBeProvided"); } + get => GetString("Antiforgery_HeaderToken_MustBeProvided"); } /// /// The required antiforgery header value "{0}" is not present. /// internal static string FormatAntiforgery_HeaderToken_MustBeProvided(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("Antiforgery_HeaderToken_MustBeProvided"), p0); - } + => string.Format(CultureInfo.CurrentCulture, GetString("Antiforgery_HeaderToken_MustBeProvided"), p0); /// /// The required antiforgery request token was not provided in either form field "{0}" or header value "{1}". /// internal static string Antiforgery_RequestToken_MustBeProvided { - get { return GetString("Antiforgery_RequestToken_MustBeProvided"); } + get => GetString("Antiforgery_RequestToken_MustBeProvided"); } /// /// The required antiforgery request token was not provided in either form field "{0}" or header value "{1}". /// internal static string FormatAntiforgery_RequestToken_MustBeProvided(object p0, object p1) - { - return string.Format(CultureInfo.CurrentCulture, GetString("Antiforgery_RequestToken_MustBeProvided"), p0, p1); - } + => string.Format(CultureInfo.CurrentCulture, GetString("Antiforgery_RequestToken_MustBeProvided"), p0, p1); /// /// The required antiforgery request token must be provided. /// internal static string Antiforgery_RequestToken_MustBeProvided_Generic { - get { return GetString("Antiforgery_RequestToken_MustBeProvided_Generic"); } + get => GetString("Antiforgery_RequestToken_MustBeProvided_Generic"); } /// /// The required antiforgery request token must be provided. /// internal static string FormatAntiforgery_RequestToken_MustBeProvided_Generic() + => GetString("Antiforgery_RequestToken_MustBeProvided_Generic"); + + /// + /// The antiforgery system has the configuration value {optionName} = {value}, but the current request is not an SSL request. + /// + internal static string Antiforgery_RequiresSSL { - return GetString("Antiforgery_RequestToken_MustBeProvided_Generic"); + get => GetString("Antiforgery_RequiresSSL"); } + /// + /// The antiforgery system has the configuration value {optionName} = {value}, but the current request is not an SSL request. + /// + internal static string FormatAntiforgery_RequiresSSL(object optionName, object value) + => string.Format(CultureInfo.CurrentCulture, GetString("Antiforgery_RequiresSSL", "optionName", "value"), optionName, value); + /// /// Value cannot be null or empty. /// internal static string ArgumentCannotBeNullOrEmpty { - get { return GetString("ArgumentCannotBeNullOrEmpty"); } + get => GetString("ArgumentCannotBeNullOrEmpty"); } /// /// Value cannot be null or empty. /// internal static string FormatArgumentCannotBeNullOrEmpty() - { - return GetString("ArgumentCannotBeNullOrEmpty"); - } + => GetString("ArgumentCannotBeNullOrEmpty"); private static string GetString(string name, params string[] formatterNames) { diff --git a/src/Microsoft.AspNetCore.Antiforgery/Resources.resx b/src/Microsoft.AspNetCore.Antiforgery/Resources.resx index bda2f0f..eeda70b 100644 --- a/src/Microsoft.AspNetCore.Antiforgery/Resources.resx +++ b/src/Microsoft.AspNetCore.Antiforgery/Resources.resx @@ -139,10 +139,6 @@ The provided antiforgery token was meant for user "{0}", but the current user is "{1}". - - The antiforgery system has the configuration value {0}.{1} = {2}, but the current request is not an SSL request. - 0 = nameof(AntiforgeryOptions), 1 = nameof(RequireSsl), 2 = bool.TrueString - The antiforgery cookie token is invalid. @@ -164,6 +160,9 @@ The required antiforgery request token must be provided. + + The antiforgery system has the configuration value {optionName} = {value}, but the current request is not an SSL request. + Value cannot be null or empty. diff --git a/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/AntiforgeryOptionsSetupTest.cs b/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/AntiforgeryOptionsSetupTest.cs index 181c62b..d901eb9 100644 --- a/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/AntiforgeryOptionsSetupTest.cs +++ b/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/AntiforgeryOptionsSetupTest.cs @@ -28,7 +28,7 @@ public void AntiforgeryOptionsSetup_SetsDefaultCookieName_BasedOnApplicationId( var options = services.GetRequiredService>(); // Act - var cookieName = options.Value.CookieName; + var cookieName = options.Value.Cookie.Name; // Assert Assert.Equal(expectedCookieName, cookieName); @@ -41,8 +41,8 @@ public void AntiforgeryOptionsSetup_UserOptionsSetup_CanSetCookieName() var serviceCollection = new ServiceCollection(); serviceCollection.Configure(o => { - Assert.Null(o.CookieName); - o.CookieName = "antiforgery"; + Assert.Null(o.Cookie.Name); + o.Cookie.Name = "antiforgery"; }); serviceCollection.AddAntiforgery(); serviceCollection @@ -53,7 +53,7 @@ public void AntiforgeryOptionsSetup_UserOptionsSetup_CanSetCookieName() var options = services.GetRequiredService>(); // Act - var cookieName = options.Value.CookieName; + var cookieName = options.Value.Cookie.Name; // Assert Assert.Equal("antiforgery", cookieName); diff --git a/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTest.cs b/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTest.cs index e9b56f1..4eebaad 100644 --- a/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTest.cs +++ b/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTest.cs @@ -28,9 +28,12 @@ public async Task ChecksSSL_ValidateRequestAsync_Throws() { // Arrange var httpContext = GetHttpContext(); - var options = new AntiforgeryOptions() + var options = new AntiforgeryOptions { +#pragma warning disable CS0618 + // obsolete property still forwards to correctly to the new API RequireSsl = true +#pragma warning restore CS0618 }; var antiforgery = GetAntiforgery(httpContext, options); @@ -38,7 +41,7 @@ public async Task ChecksSSL_ValidateRequestAsync_Throws() var exception = await Assert.ThrowsAsync( () => antiforgery.ValidateRequestAsync(httpContext)); Assert.Equal( - @"The antiforgery system has the configuration value AntiforgeryOptions.RequireSsl = true, " + + @"The antiforgery system has the configuration value AntiforgeryOptions.Cookie.SecurePolicy = Always, " + "but the current request is not an SSL request.", exception.Message); } @@ -50,7 +53,7 @@ public async Task ChecksSSL_IsRequestValidAsync_Throws() var httpContext = GetHttpContext(); var options = new AntiforgeryOptions() { - RequireSsl = true + Cookie = { SecurePolicy = CookieSecurePolicy.Always } }; var antiforgery = GetAntiforgery(httpContext, options); @@ -59,7 +62,7 @@ public async Task ChecksSSL_IsRequestValidAsync_Throws() var exception = await Assert.ThrowsAsync( () => antiforgery.IsRequestValidAsync(httpContext)); Assert.Equal( - @"The antiforgery system has the configuration value AntiforgeryOptions.RequireSsl = true, " + + @"The antiforgery system has the configuration value AntiforgeryOptions.Cookie.SecurePolicy = Always, " + "but the current request is not an SSL request.", exception.Message); } @@ -71,7 +74,7 @@ public void ChecksSSL_GetAndStoreTokens_Throws() var httpContext = GetHttpContext(); var options = new AntiforgeryOptions() { - RequireSsl = true + Cookie = { SecurePolicy = CookieSecurePolicy.Always } }; var antiforgery = GetAntiforgery(httpContext, options); @@ -80,7 +83,7 @@ public void ChecksSSL_GetAndStoreTokens_Throws() var exception = Assert.Throws( () => antiforgery.GetAndStoreTokens(httpContext)); Assert.Equal( - @"The antiforgery system has the configuration value AntiforgeryOptions.RequireSsl = true, " + + @"The antiforgery system has the configuration value AntiforgeryOptions.Cookie.SecurePolicy = Always, " + "but the current request is not an SSL request.", exception.Message); } @@ -92,7 +95,7 @@ public void ChecksSSL_GetTokens_Throws() var httpContext = GetHttpContext(); var options = new AntiforgeryOptions() { - RequireSsl = true + Cookie = { SecurePolicy = CookieSecurePolicy.Always } }; var antiforgery = GetAntiforgery(httpContext, options); @@ -101,7 +104,7 @@ public void ChecksSSL_GetTokens_Throws() var exception = Assert.Throws( () => antiforgery.GetTokens(httpContext)); Assert.Equal( - @"The antiforgery system has the configuration value AntiforgeryOptions.RequireSsl = true, " + + @"The antiforgery system has the configuration value AntiforgeryOptions.Cookie.SecurePolicy = Always, " + "but the current request is not an SSL request.", exception.Message); } @@ -113,7 +116,7 @@ public void ChecksSSL_SetCookieTokenAndHeader_Throws() var httpContext = GetHttpContext(); var options = new AntiforgeryOptions() { - RequireSsl = true + Cookie = { SecurePolicy = CookieSecurePolicy.Always } }; var antiforgery = GetAntiforgery(httpContext, options); @@ -122,7 +125,7 @@ public void ChecksSSL_SetCookieTokenAndHeader_Throws() var exception = Assert.Throws( () => antiforgery.SetCookieTokenAndHeader(httpContext)); Assert.Equal( - @"The antiforgery system has the configuration value AntiforgeryOptions.RequireSsl = true, " + + @"The antiforgery system has the configuration value AntiforgeryOptions.Cookie.SecurePolicy = Always, " + "but the current request is not an SSL request.", exception.Message); } @@ -745,7 +748,7 @@ public async Task ValidateRequestAsync_NoCookieToken_Throws() // Arrange var context = CreateMockContext(new AntiforgeryOptions() { - CookieName = "cookie-name", + Cookie = { Name = "cookie-name" }, FormFieldName = "form-field-name", HeaderName = null, }); @@ -769,7 +772,7 @@ public async Task ValidateRequestAsync_NonFormRequest_HeaderDisabled_Throws() // Arrange var context = CreateMockContext(new AntiforgeryOptions() { - CookieName = "cookie-name", + Cookie = { Name = "cookie-name" }, FormFieldName = "form-field-name", HeaderName = null, }); @@ -793,7 +796,7 @@ public async Task ValidateRequestAsync_NonFormRequest_NoHeaderValue_Throws() // Arrange var context = CreateMockContext(new AntiforgeryOptions() { - CookieName = "cookie-name", + Cookie = { Name = "cookie-name" }, FormFieldName = "form-field-name", HeaderName = "header-name", }); @@ -819,7 +822,7 @@ public async Task ValidateRequestAsync_FormRequest_NoRequestTokenValue_Throws() // Arrange var context = CreateMockContext(new AntiforgeryOptions() { - CookieName = "cookie-name", + Cookie = { Name = "cookie-name" }, FormFieldName = "form-field-name", HeaderName = "header-name", }); diff --git a/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenStoreTest.cs b/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenStoreTest.cs index 96fd270..c66d31d 100644 --- a/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenStoreTest.cs +++ b/test/Microsoft.AspNetCore.Antiforgery.Test/Internal/DefaultAntiforgeryTokenStoreTest.cs @@ -21,9 +21,9 @@ public void GetCookieToken_CookieDoesNotExist_ReturnsNull() { // Arrange var httpContext = GetHttpContext(new RequestCookieCollection()); - var options = new AntiforgeryOptions() + var options = new AntiforgeryOptions { - CookieName = _cookieName + Cookie = { Name = _cookieName } }; var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options)); @@ -40,9 +40,9 @@ public void GetCookieToken_CookieIsEmpty_ReturnsNull() { // Arrange var httpContext = GetHttpContext(_cookieName, string.Empty); - var options = new AntiforgeryOptions() + var options = new AntiforgeryOptions { - CookieName = _cookieName + Cookie = { Name = _cookieName } }; var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options)); @@ -61,9 +61,9 @@ public void GetCookieToken_CookieIsNotEmpty_ReturnsToken() var expectedToken = "valid-value"; var httpContext = GetHttpContext(_cookieName, expectedToken); - var options = new AntiforgeryOptions() + var options = new AntiforgeryOptions { - CookieName = _cookieName + Cookie = { Name = _cookieName } }; var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options)); @@ -82,9 +82,9 @@ public async Task GetRequestTokens_CookieIsEmpty_ReturnsNullTokens() var httpContext = GetHttpContext(new RequestCookieCollection()); httpContext.Request.Form = FormCollection.Empty; - var options = new AntiforgeryOptions() + var options = new AntiforgeryOptions { - CookieName = "cookie-name", + Cookie = { Name = "cookie-name" }, FormFieldName = "form-field-name", }; @@ -110,9 +110,9 @@ public async Task GetRequestTokens_HeaderTokenTakensPriority_OverFormToken() }); // header value has priority. httpContext.Request.Headers.Add("header-name", "header-value"); - var options = new AntiforgeryOptions() + var options = new AntiforgeryOptions { - CookieName = "cookie-name", + Cookie = { Name = "cookie-name" }, FormFieldName = "form-field-name", HeaderName = "header-name", }; @@ -138,9 +138,9 @@ public async Task GetRequestTokens_NoHeaderToken_FallsBackToFormToken() { "form-field-name", "form-value" }, }); - var options = new AntiforgeryOptions() + var options = new AntiforgeryOptions { - CookieName = "cookie-name", + Cookie = { Name = "cookie-name" }, FormFieldName = "form-field-name", HeaderName = "header-name", }; @@ -166,9 +166,9 @@ public async Task GetRequestTokens_NonFormContentType_UsesHeaderToken() // Will not be accessed httpContext.Request.Form = null; - var options = new AntiforgeryOptions() + var options = new AntiforgeryOptions { - CookieName = "cookie-name", + Cookie = { Name = "cookie-name" }, FormFieldName = "form-field-name", HeaderName = "header-name", }; @@ -193,9 +193,9 @@ public async Task GetRequestTokens_NoHeaderToken_NonFormContentType_ReturnsNullT // Will not be accessed httpContext.Request.Form = null; - var options = new AntiforgeryOptions() + var options = new AntiforgeryOptions { - CookieName = "cookie-name", + Cookie = { Name = "cookie-name" }, FormFieldName = "form-field-name", HeaderName = "header-name", }; @@ -218,9 +218,9 @@ public async Task GetRequestTokens_BothHeaderValueAndFormFieldsEmpty_ReturnsNull httpContext.Request.ContentType = "application/x-www-form-urlencoded"; httpContext.Request.Form = FormCollection.Empty; - var options = new AntiforgeryOptions() + var options = new AntiforgeryOptions { - CookieName = "cookie-name", + Cookie = { Name = "cookie-name" }, FormFieldName = "form-field-name", HeaderName = "header-name", }; @@ -236,9 +236,9 @@ public async Task GetRequestTokens_BothHeaderValueAndFormFieldsEmpty_ReturnsNull } [Theory] - [InlineData(true, true)] - [InlineData(false, null)] - public void SaveCookieToken(bool requireSsl, bool? expectedCookieSecureFlag) + [InlineData(CookieSecurePolicy.Always, true)] + [InlineData(CookieSecurePolicy.None, null)] + public void SaveCookieToken(CookieSecurePolicy policy, bool? expectedCookieSecureFlag) { // Arrange var token = "serialized-value"; @@ -255,8 +255,11 @@ public void SaveCookieToken(bool requireSsl, bool? expectedCookieSecureFlag) var options = new AntiforgeryOptions() { - CookieName = _cookieName, - RequireSsl = requireSsl + Cookie = + { + Name = _cookieName, + SecurePolicy = policy + }, }; var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options)); @@ -294,8 +297,10 @@ public void SaveCookieToken_SetsCookieWithApproriatePathBase(string requestPathB httpContext .SetupGet(hc => hc.Request.Path) .Returns("/index.html"); - var options = new AntiforgeryOptions(); - options.CookieName = _cookieName; + var options = new AntiforgeryOptions + { + Cookie = { Name = _cookieName } + }; var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options)); // Act @@ -328,9 +333,14 @@ public void SaveCookieToken_NonNullAntiforgeryOptionsConfigureCookieOptionsPath_ httpContext .SetupGet(hc => hc.Request.Path) .Returns("/index.html"); - var options = new AntiforgeryOptions(); - options.CookieName = _cookieName; - options.ConfigureCookieOptions = (context, cookieOptions) => cookieOptions.Path = expectedCookiePath; + var options = new AntiforgeryOptions + { + Cookie = + { + Name = _cookieName, + Path = expectedCookiePath + } + }; var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options)); // Act @@ -362,9 +372,14 @@ public void SaveCookieToken_NonNullAntiforgeryOptionsConfigureCookieOptionsDomai httpContext .SetupGet(hc => hc.Request.Path) .Returns("/index.html"); - var options = new AntiforgeryOptions(); - options.CookieName = _cookieName; - options.ConfigureCookieOptions = (context, cookieOptions) => cookieOptions.Domain = expectedCookieDomain; + var options = new AntiforgeryOptions + { + Cookie = + { + Name = _cookieName, + Domain = expectedCookieDomain + } + }; var tokenStore = new DefaultAntiforgeryTokenStore(new TestOptionsManager(options)); // Act @@ -407,10 +422,10 @@ private class MockResponseCookieCollection : IResponseCookies public void Append(string key, string value, CookieOptions options) { - this.Key = key; - this.Value = value; - this.Options = options; - this.Count++; + Key = key; + Value = value; + Options = options; + Count++; } public void Append(string key, string value)