diff --git a/dotnet/src/webdriver/Cookie.cs b/dotnet/src/webdriver/Cookie.cs index 6ac99b0c68bcd..5d892fdc33706 100644 --- a/dotnet/src/webdriver/Cookie.cs +++ b/dotnet/src/webdriver/Cookie.cs @@ -17,6 +17,7 @@ // using System; +using System.Linq; using System.Collections.Generic; using System.Globalization; using Newtonsoft.Json; @@ -35,8 +36,11 @@ public class Cookie private string cookieValue; private string cookiePath; private string cookieDomain; + private bool isHttpOnly; private string sameSite; + private bool secure; private DateTime? cookieExpiry; + private readonly string[] sameSiteValues = {"Strict", "Lax", "None"}; /// /// Initializes a new instance of the class with a specific name, @@ -98,6 +102,44 @@ public Cookie(string name, string value, string path, DateTime? expiry) { } + /// + /// Initializes a new instance of the class with a specific name, + /// value, domain, path and expiration date. + /// + /// The name of the cookie. + /// The value of the cookie. + /// The domain of the cookie. + /// The path of the cookie. + /// The expiration date of the cookie. + /// if the cookie is secure; otherwise + /// if the cookie is an HTTP-only cookie; otherwise + /// The SameSite value of cookie. + /// If the name is or an empty string, + /// or if it contains a semi-colon. + /// If the value or currentUrl is . + /// If the same site value is not valid or same site value is "None" but secure is set to false. + public Cookie(string name, string value, string domain, string path, DateTime? expiry, bool secure, bool isHttpOnly, string sameSite) + : this(name, value, domain, path, expiry) + { + this.isHttpOnly = isHttpOnly; + this.secure = secure; + + if (!string.IsNullOrEmpty(sameSite)) + { + if (!sameSiteValues.Contains(sameSite)) + { + throw new ArgumentException("Invalid sameSite cookie value. It should either \"Lax\", \"Strict\" or \"None\" ", "sameSite"); + } + + if ("None".Equals(sameSite) && !this.secure) + { + throw new ArgumentException("Invalid cookie configuration: SameSite=None must be Secure"); + } + + this.sameSite = sameSite; + } + } + /// /// Initializes a new instance of the class with a specific name, /// value, and path. @@ -168,7 +210,7 @@ public virtual string Path [JsonProperty("secure")] public virtual bool Secure { - get { return false; } + get { return this.secure; } } /// @@ -177,7 +219,8 @@ public virtual bool Secure [JsonProperty("httpOnly")] public virtual bool IsHttpOnly { - get { return false; } + get { return this.isHttpOnly; } + } /// @@ -187,7 +230,6 @@ public virtual bool IsHttpOnly public virtual string SameSite { get { return this.sameSite; } - protected set { this.sameSite = value; } } /// @@ -287,7 +329,8 @@ public override string ToString() return this.cookieName + "=" + this.cookieValue + (this.cookieExpiry == null ? string.Empty : "; expires=" + this.cookieExpiry.Value.ToUniversalTime().ToString("ddd MM dd yyyy hh:mm:ss UTC", CultureInfo.InvariantCulture)) + (string.IsNullOrEmpty(this.cookiePath) ? string.Empty : "; path=" + this.cookiePath) - + (string.IsNullOrEmpty(this.cookieDomain) ? string.Empty : "; domain=" + this.cookieDomain); + + (string.IsNullOrEmpty(this.cookieDomain) ? string.Empty : "; domain=" + this.cookieDomain) + + "; isHttpOnly= " + this.isHttpOnly + "; secure= " + this.secure + (string.IsNullOrEmpty(this.sameSite) ? string.Empty : "; sameSite=" + this.sameSite); } /// diff --git a/dotnet/src/webdriver/Internal/ReturnedCookie.cs b/dotnet/src/webdriver/Internal/ReturnedCookie.cs index 7d18ab6fba576..a55ca279edc55 100644 --- a/dotnet/src/webdriver/Internal/ReturnedCookie.cs +++ b/dotnet/src/webdriver/Internal/ReturnedCookie.cs @@ -26,9 +26,7 @@ namespace OpenQA.Selenium.Internal /// public class ReturnedCookie : Cookie { - private bool isSecure; - private bool isHttpOnly; - + /// /// Initializes a new instance of the class with a specific name, /// value, domain, path and expiration date. @@ -64,27 +62,9 @@ public ReturnedCookie(string name, string value, string domain, string path, Dat /// or if it contains a semi-colon. /// If the value or currentUrl is . public ReturnedCookie(string name, string value, string domain, string path, DateTime? expiry, bool isSecure, bool isHttpOnly, string sameSite) - : base(name, value, domain, path, expiry) - { - this.isSecure = isSecure; - this.isHttpOnly = isHttpOnly; - this.SameSite = sameSite; - } - - /// - /// Gets a value indicating whether the cookie is secure. - /// - public override bool Secure - { - get { return this.isSecure; } - } - - /// - /// Gets a value indicating whether the cookie is an HTTP-only cookie. - /// - public override bool IsHttpOnly + : base(name, value, domain, path, expiry, isSecure, isHttpOnly, sameSite) { - get { return this.isHttpOnly; } + } /// @@ -97,8 +77,9 @@ public override string ToString() + (this.Expiry == null ? string.Empty : "; expires=" + this.Expiry.Value.ToUniversalTime().ToString("ddd MM/dd/yyyy HH:mm:ss UTC", CultureInfo.InvariantCulture)) + (string.IsNullOrEmpty(this.Path) ? string.Empty : "; path=" + this.Path) + (string.IsNullOrEmpty(this.Domain) ? string.Empty : "; domain=" + this.Domain) - + (this.isSecure ? "; secure" : string.Empty) - + (this.isHttpOnly ? "; httpOnly" : string.Empty); + + (this.Secure ? "; secure" : string.Empty) + + (this.IsHttpOnly ? "; httpOnly" : string.Empty) + + (string.IsNullOrEmpty(this.SameSite) ? string.Empty : "; sameSite=" + this.SameSite); } } } diff --git a/dotnet/test/common/CookieTest.cs b/dotnet/test/common/CookieTest.cs index bb168038a1c71..e40c248fbcffc 100644 --- a/dotnet/test/common/CookieTest.cs +++ b/dotnet/test/common/CookieTest.cs @@ -25,6 +25,30 @@ public void ShouldThrowAnExceptionWhenTheNameIsNull() Assert.That(() => new ReturnedCookie(null, "value", null, null, DateTime.Now, false, false), Throws.InstanceOf()); } + [Test] + public void ShouldThrowAnExceptionWhenSameSiteIsWrong() + { + Assert.That(() => new ReturnedCookie("name", "value", "" , "/", DateTime.Now, true, true, "Wrong"), Throws.InstanceOf()); + } + + [Test] + public void ShouldThrowAnExceptionWhenSameSiteIsNoneButNotSecure() + { + Assert.That(() => new ReturnedCookie("name", "value", "", "/", DateTime.Now, false, true, "None"), Throws.InstanceOf()); + } + + [Test] + public void CookiesShouldAllowOptionalParametersToBeSet() + { + DateTime expiry = DateTime.Now; + Cookie cookie = new Cookie ("name", "value", "test.com", "/", expiry, true, true, "None"); + Assert.That(cookie.Domain, Is.EqualTo("test.com")); + Assert.That(cookie.Path, Is.EqualTo("/")); + Assert.That(cookie.IsHttpOnly, Is.True); + Assert.That(cookie.Secure, Is.True); + Assert.That(cookie.SameSite, Is.EqualTo("None")); + } + [Test] public void CookiesShouldAllowSecureToBeSet() {