示例#1
0
        /// <summary>
        /// Create a cookie for the browser by adding it to the HTTP Response.
        /// </summary>
        /// <param name="httpContext">HTTP context.</param>
        /// <param name="name">Name of the cookie.</param>
        /// <param name="value">Value associated with the cookie.</param>
        /// <param name="domain">Domain associated with the cookie.</param>
        /// <param name="expires">Expiration date and time for the cookie.</param>
        /// <param name="sameSite">Same site enforcement mode associated with the cookie.</param>
        /// <exception cref="ArgumentNullException">Cookie name is either null or empty.</exception>
        public static void CookieCreate(this HttpContextBase httpContext,
                                        string name,
                                        string value,
                                        string domain         = null,
                                        DateTime?expires      = null,
                                        SameSiteMode sameSite = SameSiteMode.None)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException(nameof(name));
            }

            HttpCookie cookie = new HttpCookie(name)
            {
                SameSite = sameSite,
                Value    = value
            };

            if (!string.IsNullOrWhiteSpace(domain))
            {
                cookie.Domain = domain;
            }

            if (expires.HasValue)
            {
                cookie.Expires = expires.Value;
            }

            httpContext.Response.Cookies.Add(cookie);
        }
示例#2
0
        /// <summary>
        /// Parses samesite option value.
        /// </summary>
        /// <param name="samesite">One of: None|Lax|Strict. Case insensitive.</param>
        /// <param name="mode">Parsed value.</param>
        /// <returns>Whether the value was parsed.</returns>
        public static bool TryParseSameSite(string samesite, out SameSiteMode mode)
        {
            if (samesite != null)
            {
                // return s_options.TryGetValue(samesite, out mode); // overhead

                // return Enum.TryParse<SameSiteMode>(samesite, true, out mode); // accepts numbers as well

                if (samesite.Equals(nameof(SameSiteMode.None), StringComparison.OrdinalIgnoreCase))
                {
                    mode = SameSiteMode.None;
                    return(true);
                }

                if (samesite.Equals(nameof(SameSiteMode.Lax), StringComparison.OrdinalIgnoreCase))
                {
                    mode = SameSiteMode.Lax;
                    return(true);
                }

                if (samesite.Equals(nameof(SameSiteMode.Strict), StringComparison.OrdinalIgnoreCase))
                {
                    mode = SameSiteMode.Strict;
                    return(true);
                }
            }

            // default
            mode = SameSiteMode.Lax;
            return(false);
        }
示例#3
0
 private static string?MapSameSiteMode(SameSiteMode value)
 {
     return(value switch
     {
         SameSiteMode.None => "none",
         SameSiteMode.Lax => "lax",
         SameSiteMode.Strict => "strict",
         _ => null
     });
示例#4
0
        /// <summary>
        /// Register cookie authentication related actors
        /// </summary>
        /// <remarks>
        /// Remember to configure 'UseCookieAuthentication()' and 'UseAuthorization()'
        /// after 'UseRouting()', but before 'UseEndpoints()'
        /// </remarks>
        /// <param name="services"></param>
        /// <param name="configRoot"></param>
        /// <param name="mode"></param>
        public static AuthenticationBuilder AddCookieAuthentication(
            this IServiceCollection services,
            IConfigurationRoot configRoot,
            SameSiteMode mode = SameSiteMode.Lax
            )
        {
            var config = configRoot
                         .GetSection(WebConfiguration.AUTHENTICATION)
                         .GetSection(WebConfiguration.AUTHENTICATION_COOKIE)
                         .Get <CookieAuthenticationConfiguration>();

            if (config == null)
            {
                var configPath = $"{WebConfiguration.AUTHENTICATION}:{WebConfiguration.AUTHENTICATION_COOKIE}";
                throw new Exception($"Unable to find configuration for '{configPath}' <CookieAuthenticationConfiguration>");
            }

            var cookie = new CookieBuilder
            {
                Name     = config.CookieName,
                SameSite = mode
            };

            var cookieEvents = new CookieAuthenticationEvents
            {
                OnRedirectToAccessDenied = context =>
                {
                    context.Response.StatusCode = 403; // Don't redirect, set to forbidden
                    return(Task.CompletedTask);
                },
                OnRedirectToLogin = context =>
                {
                    context.Response.StatusCode = 401; // Don't redirect, set to unauthorized
                    return(Task.CompletedTask);
                }
            };

            services.AddSingleton((sp) => config);

            // Register actors
            return(services
                   .AddAuthentication((options) =>
            {
                options.DefaultAuthenticateScheme =
                    options.DefaultChallengeScheme =
                        options.DefaultScheme =
                            options.DefaultSignInScheme = config.AuthenticationScheme;
            })
                   .AddCookie(config.AuthenticationScheme, options =>
            {
                options.AccessDeniedPath = new PathString(config.AccessDeniedPath);
                options.Cookie = cookie;
                options.Events = cookieEvents;
                options.LoginPath = new PathString(config.LoginPath);
            }));
        }
示例#5
0
 internal CookieSettings(
     string name,
     bool?secure,
     bool?httpOnly,
     SameSiteMode sameSite,
     string?domainExpression)
 {
     Name             = name;
     Secure           = secure;
     HttpOnly         = httpOnly;
     SameSite         = sameSite;
     DomainExpression = domainExpression;
 }
        private void SetDefaultsFromConfig()
        {
            HttpCookiesSection config = RuntimeConfig.GetConfig().HttpCookies;

            _secure   = config.RequireSSL;
            _httpOnly = config.HttpOnlyCookies;
            _sameSite = config.SameSite;

            if (config.Domain != null && config.Domain.Length > 0)
            {
                _domain = config.Domain;
            }
        }
示例#7
0
        /// <summary>
        /// Stores a value in a user Cookie, creating it if it doesn't exists yet.
        /// </summary>
        /// <param name="cookieName">Cookie name</param>
        /// <param name="cookieDomain">Cookie domain (or NULL to use default domain value)</param>
        /// <param name="keyName">Cookie key name (if the cookie is a keyvalue pair): if NULL or EMPTY, the cookie will be treated as a single variable.</param>
        /// <param name="value">Value to store into the cookie</param>
        /// <param name="expirationDate">Expiration Date (set it to NULL to leave default expiration date)</param>
        /// <param name="httpOnly">set it to TRUE to enable HttpOnly, FALSE otherwise (default: false)</param>
        /// <param name="sameSite">set it to 'None', 'Lax', 'Strict' or '(-1)' to not add it (default: '(-1)').</param>
        /// <param name="secure">set it to TRUE to enable Secure (HTTPS only), FALSE otherwise</param>
        public static void StoreInCookie(
            string cookieName,
            string cookieDomain,
            IDictionary <string, string> keyValuePairs,
            DateTime?expirationDate,
            bool httpOnly         = false,
            SameSiteMode sameSite = (SameSiteMode)(-1),
            bool secure           = false)
        {
            // NOTE: we have to look first in the response, and then in the request.
            // This is required when we update multiple keys inside the cookie.
            HttpCookie cookie = HttpContext.Current.Response.Cookies.AllKeys.Contains(cookieName)
                ? HttpContext.Current.Response.Cookies[cookieName]
                : HttpContext.Current.Request.Cookies[cookieName];

            if (cookie == null)
            {
                cookie = new HttpCookie(cookieName);
            }

            if (keyValuePairs == null || keyValuePairs.Count == 0)
            {
                cookie.Value = null;
            }
            else
            {
                foreach (var pair in keyValuePairs)
                {
                    cookie.Values.Set(pair.Key, pair.Value);
                }
            }

            if (expirationDate.HasValue)
            {
                cookie.Expires = expirationDate.Value;
            }
            if (!String.IsNullOrEmpty(cookieDomain))
            {
                cookie.Domain = cookieDomain;
            }
            if (httpOnly)
            {
                cookie.HttpOnly = true;
            }

            cookie.Secure   = secure;
            cookie.SameSite = sameSite;
            HttpContext.Current.Response.Cookies.Set(cookie);
        }
示例#8
0
        private void PersistCookie(string name, string value, TimeSpan?maxAge, SameSiteMode sameSite, bool httpOnly, bool secure)
        {
            if (value == null)
            {
                value = string.Empty;
            }
            int cookieSeriesCount = value.Length * 2 / maxCookieSizeBytes + 1;

            if (cookieSeriesCount > maxCookiesPerDomain)
            {
                throw new Exception("Cookie too large");
            }

            int x;

            for (x = 0; x < cookieSeriesCount; x++)
            {
                string seriesName  = x == 0 ? name : $"{name}-{x}";
                string seriesValue = value.Substring(x * maxCookieSizeBytes / 2, Math.Min(maxCookieSizeBytes / 2, value.Length - x * maxCookieSizeBytes / 2));

                context.Response.Cookies.Delete(seriesName);
                context.Response.Cookies.Append(seriesName, seriesValue, new CookieOptions()
                {
                    Path     = "/",
                    SameSite = sameSite,
                    Secure   = secure,
                    HttpOnly = httpOnly,
                    MaxAge   = maxAge,
                    Expires  = maxAge.HasValue ? DateTimeOffset.UtcNow.Add(maxAge.Value) : (DateTimeOffset?)null
                });
            }
            for (int y = x; y < maxCookiesPerDomain; y++)
            {
                string seriesName = y == 0 ? name : $"{name}-{y}";
                if (context.Request.Cookies.Keys.Contains(seriesName))
                {
                    context.Response.Cookies.Delete(seriesName);
                    context.Response.Cookies.Append(seriesName, string.Empty, new CookieOptions()
                    {
                        Path    = "/",
                        MaxAge  = new TimeSpan(0),
                        Expires = DateTimeOffset.MinValue
                    });
                }
            }
        }
示例#9
0
        private static string GetStringRepresentationOfSameSite(SameSiteMode siteMode)
        {
            switch (siteMode)
            {
            case SameSiteMode.None:
                return("None");

            case SameSiteMode.Lax:
                return("Lax");

            case SameSiteMode.Strict:
                return("Strict");

            default:
                throw new ArgumentOutOfRangeException("siteMode",
                                                      string.Format(CultureInfo.InvariantCulture, "Unexpected SameSiteMode value: {0}", siteMode));
            }
        }
示例#10
0
 private void DeleteCookie(string name, SameSiteMode sameSite, bool httpOnly, bool secure)
 {
     for (int x = 0; x < maxCookiesPerDomain; x++)
     {
         string seriesName = x == 0 ? name : $"{name}-{x}";
         if (context.Request.Cookies.Keys.Contains(seriesName))
         {
             context.Response.Cookies.Delete(seriesName);
             context.Response.Cookies.Append(seriesName, string.Empty, new CookieOptions()
             {
                 Path     = "/",
                 MaxAge   = new TimeSpan(0),
                 Expires  = DateTimeOffset.MinValue,
                 SameSite = sameSite,
                 HttpOnly = httpOnly,
                 Secure   = secure
             });
         }
     }
 }
示例#11
0
        public void HandleSameSiteCookieCompatibility_Default_ExecutesSuccessfully(SameSiteMode initialSameSiteMode, SameSiteMode expectedSameSiteMode, string userAgent)
        {
            _httpContext.Request.Headers.Add(_userAgentHeaderName, userAgent);
            var appendCookieOptions = new CookieOptions()
            {
                SameSite = initialSameSiteMode
            };
            var deleteCookieOptions = new CookieOptions()
            {
                SameSite = initialSameSiteMode
            };
            var appendCookieContext = new AppendCookieContext(_httpContext, appendCookieOptions, _cookieName, _cookieValue);
            var deleteCookieContext = new DeleteCookieContext(_httpContext, deleteCookieOptions, _cookieName);

            _cookiePolicyOptions.HandleSameSiteCookieCompatibility();

            Assert.Equal(SameSiteMode.Unspecified, _cookiePolicyOptions.MinimumSameSitePolicy);

            _cookiePolicyOptions.OnAppendCookie(appendCookieContext);
            Assert.Equal(expectedSameSiteMode, appendCookieOptions.SameSite);

            _cookiePolicyOptions.OnDeleteCookie(deleteCookieContext);
            Assert.Equal(expectedSameSiteMode, deleteCookieOptions.SameSite);
        }
示例#12
0
 /// <inheritdoc />
 public IAndResponseCookieTestBuilder WithSameSite(SameSiteMode sameSite)
 {
     this.responseCookie.SameSite = sameSite;
     this.validations.Add((expected, actual) => expected.SameSite == actual.SameSite);
     return(this);
 }
        /// <summary>
        /// Converts the specified string representation of an HTTP cookie to HttpCookie
        /// </summary>
        /// <param name="input"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public static bool TryParse(string input, out HttpCookie result)
        {
            result = null;

            if (string.IsNullOrEmpty(input))
            {
                return(false);
            }

            // The substring before the first ';' is cookie-pair, with format of cookiename[=key1=val2&key2=val2&...]
            int    dividerIndex = input.IndexOf(';');
            string cookiePair   = dividerIndex >= 0 ? input.Substring(0, dividerIndex) : input;

            HttpCookie cookie = HttpRequest.CreateCookieFromString(cookiePair.Trim());

            // If there was no cookie name being created, stop parsing and return
            if (string.IsNullOrEmpty(cookie.Name))
            {
                return(false);
            }

            //
            // Parse the collections of cookie-av
            // cookie-av = expires-av/max-age-av/domain-av/path-av/secure-av/httponly-av/extension-av
            // https://tools.ietf.org/html/rfc6265

            while (dividerIndex >= 0 && dividerIndex < input.Length - 1)
            {
                int cookieAvStartIndex = dividerIndex + 1;
                dividerIndex = input.IndexOf(';', cookieAvStartIndex);
                string cookieAv = dividerIndex >= 0 ? input.Substring(cookieAvStartIndex, dividerIndex - cookieAvStartIndex).Trim() : input.Substring(cookieAvStartIndex).Trim();

                int    assignmentIndex = cookieAv.IndexOf('=');
                string attributeName   = assignmentIndex >= 0 ? cookieAv.Substring(0, assignmentIndex).Trim() : cookieAv;
                string attributeValue  = assignmentIndex >= 0 && assignmentIndex < cookieAv.Length - 1 ? cookieAv.Substring(assignmentIndex + 1).Trim() : null;

                //
                // Parse supported cookie-av Attribute

                //
                // Expires
                if (StringUtil.EqualsIgnoreCase(attributeName, "Expires"))
                {
                    DateTime dt;
                    if (DateTime.TryParse(attributeValue, out dt))
                    {
                        cookie.Expires = dt;
                    }
                }
                //
                // Domain
                else if (attributeValue != null && StringUtil.EqualsIgnoreCase(attributeName, "Domain"))
                {
                    cookie.Domain = attributeValue;
                }
                //
                // Path
                else if (attributeValue != null && StringUtil.EqualsIgnoreCase(attributeName, "Path"))
                {
                    cookie.Path = attributeValue;
                }
                //
                // Secure
                else if (StringUtil.EqualsIgnoreCase(attributeName, "Secure"))
                {
                    cookie.Secure = true;
                }
                //
                // HttpOnly
                else if (StringUtil.EqualsIgnoreCase(attributeName, "HttpOnly"))
                {
                    cookie.HttpOnly = true;
                }
                //
                // SameSite
                else if (StringUtil.EqualsIgnoreCase(attributeName, "SameSite"))
                {
                    SameSiteMode sameSite = (SameSiteMode)(-1);
                    if (Enum.TryParse <SameSiteMode>(attributeValue, true, out sameSite))
                    {
                        cookie.SameSite = sameSite;
                    }
                }
            }

            result = cookie;

            return(true);
        }
示例#14
0
文件: Startup.cs 项目: mentos33/Kahla
 public Startup(IConfiguration configuration)
 {
     Configuration = configuration;
     Mode          = Convert.ToBoolean(configuration["LaxCookie"]) ? SameSiteMode.Lax : SameSiteMode.None;
 }
示例#15
0
 public void Remove(string name, SameSiteMode sameSite = SameSiteMode.Strict, bool httpOnly = true, bool secure = true)
 {
     DeleteCookie(name, sameSite, httpOnly, secure);
 }
示例#16
0
        public void AddSecure(string name, string value, TimeSpan?maxAge = null, SameSiteMode sameSite = SameSiteMode.Strict, bool httpOnly = true, bool secure = true)
        {
            var encryptedValue = Encrypt(value);

            PersistCookie(name, encryptedValue, maxAge, sameSite, httpOnly, secure);
        }
示例#17
0
 public void Add(string name, string value, TimeSpan?maxAge = null, SameSiteMode sameSite = SameSiteMode.Strict, bool httpOnly = false, bool secure = false)
 {
     PersistCookie(name, value, maxAge, sameSite, httpOnly, secure);
 }
 public Startup(IConfiguration configuration, IHostingEnvironment environment)
 {
     Environment   = environment;
     Configuration = configuration;
     Mode          = Convert.ToBoolean(configuration["LaxCookie"]) ? SameSiteMode.Lax : SameSiteMode.None;
 }
示例#19
0
        /// <summary>
        /// Add SAML 2.0 configuration.
        /// </summary>
        /// <param name="loginPath">Redirection target used by the handler.</param>
        /// <param name="slidingExpiration">If set to true the handler re-issue a new cookie with a new expiration time any time it processes a request which is more than halfway through the expiration window.</param>
        /// <param name="accessDeniedPath">If configured, access denied redirection target used by the handler.</param>
        /// <param name="sessionStore">Allow configuration of a custom ITicketStore.</param>
        public static IServiceCollection AddSaml2(this IServiceCollection services, string loginPath = "/Auth/Login", bool slidingExpiration = false, string accessDeniedPath = null, ITicketStore sessionStore = null, SameSiteMode cookieSameSite = SameSiteMode.Lax)
        {
            services.AddAuthentication(Saml2Constants.AuthenticationScheme)
            .AddCookie(Saml2Constants.AuthenticationScheme, o =>
            {
                o.LoginPath         = new PathString(loginPath);
                o.SlidingExpiration = slidingExpiration;
                if (!string.IsNullOrEmpty(accessDeniedPath))
                {
                    o.AccessDeniedPath = new PathString(accessDeniedPath);
                }
                if (sessionStore != null)
                {
                    o.SessionStore = sessionStore;
                }
                o.Cookie.SameSite = cookieSameSite;
            });

            return(services);
        }
示例#20
0
        public void HandleSameSiteCookieCompatibility_CustomFilter_ExecutesSuccessfully(SameSiteMode initialSameSiteMode, SameSiteMode expectedSameSiteMode, bool expectedEventCalled, string userAgent)
        {
            _httpContext.Request.Headers.Add(_userAgentHeaderName, userAgent);
            var appendCookieOptions = new CookieOptions()
            {
                SameSite = initialSameSiteMode
            };
            var deleteCookieOptions = new CookieOptions()
            {
                SameSite = initialSameSiteMode
            };
            var appendCookieContext = new AppendCookieContext(_httpContext, appendCookieOptions, _cookieName, _cookieValue);
            var deleteCookieContext = new DeleteCookieContext(_httpContext, deleteCookieOptions, _cookieName);
            var appendEventCalled   = false;
            var deleteEventCalled   = false;

            _cookiePolicyOptions.HandleSameSiteCookieCompatibility((userAgent) => {
                appendEventCalled = true;
                return(CookiePolicyOptionsExtensions.DisallowsSameSiteNone(userAgent));
            });

            Assert.Equal(SameSiteMode.Unspecified, _cookiePolicyOptions.MinimumSameSitePolicy);

            _cookiePolicyOptions.OnAppendCookie(appendCookieContext);
            Assert.Equal(expectedSameSiteMode, appendCookieOptions.SameSite);
            Assert.Equal(expectedEventCalled, appendEventCalled);

            _cookiePolicyOptions.HandleSameSiteCookieCompatibility((userAgent) => {
                deleteEventCalled = true;
                return(CookiePolicyOptionsExtensions.DisallowsSameSiteNone(userAgent));
            });

            _cookiePolicyOptions.OnDeleteCookie(deleteCookieContext);
            Assert.Equal(expectedSameSiteMode, deleteCookieOptions.SameSite);
            Assert.Equal(expectedEventCalled, deleteEventCalled);
        }
示例#21
0
 /// <summary>
 /// Configure application to use cookie authentication
 /// </summary>
 /// <param name="app"></param>
 /// <param name="mode"></param>
 public static IApplicationBuilder UseCookieAuthentication(this IApplicationBuilder app, SameSiteMode mode = SameSiteMode.Lax)
 => app
 .UseAuthentication()
 .UseCookiePolicy(new CookiePolicyOptions {
     MinimumSameSitePolicy = mode
 });