- * Note: This implementation is designed to be forgiving when parsing malformed
- * cookies.
+ * Note: This implementation is designed to be forgiving when parsing malformed cookies.
*/
public class CookieHeader extends Header {
private static CookieHeader valueOf(final List values) {
List cookies = new ArrayList<>(values.size());
- Integer version = null;
- Cookie cookie = new Cookie();
for (String s1 : values) {
for (String s2 : HeaderUtil.split(s1, ';')) {
String[] nvp = HeaderUtil.parseParameter(s2);
- if (nvp[0].length() > 0 && nvp[0].charAt(0) != '$') {
- if (cookie.getName() != null) {
- // existing cookie was being parsed
- cookies.add(cookie);
- }
- cookie = new Cookie();
- // inherit previous parsed version
- cookie.setVersion(version);
- cookie.setName(nvp[0]);
- cookie.setValue(nvp[1]);
- } else if ("$Version".equalsIgnoreCase(nvp[0])) {
- cookie.setVersion(version = parseInteger(nvp[1]));
- } else if ("$Path".equalsIgnoreCase(nvp[0])) {
- cookie.setPath(nvp[1]);
- } else if ("$Domain".equalsIgnoreCase(nvp[0])) {
- cookie.setDomain(nvp[1]);
- } else if ("$Port".equalsIgnoreCase(nvp[0])) {
- cookie.getPort().clear();
- parsePorts(cookie.getPort(), nvp[1]);
+ if (nvp[0].isEmpty()) {
+ continue; // ignore empty cookie pair
+ } else if (nvp[0].startsWith("$")) {
+ continue; // ignore legacy cookie attributes
+ } else if (nvp.length > 1){
+ cookies.add(new Cookie(nvp[0], nvp[1]));
}
}
}
- if (cookie.getName() != null) {
- // last cookie being parsed
- cookies.add(cookie);
- }
return new CookieHeader(cookies);
}
- private static void parsePorts(List list, String s) {
- for (String port : s.split(",")) {
- Integer p = parseInteger(port);
- if (p != null) {
- list.add(p);
- }
- }
- }
-
- private static Integer parseInteger(String s) {
- try {
- return Integer.valueOf(s);
- } catch (NumberFormatException nfe) {
- return null;
- }
- }
-
/**
* Constructs a new header, initialized from the specified request message.
*
@@ -154,52 +115,17 @@ public String getName() {
@Override
public List getValues() {
- boolean quoted = false;
- Integer version = null;
- for (Cookie cookie : cookies) {
- if (cookie.getVersion() != null && (version == null || cookie.getVersion() > version)) {
- version = cookie.getVersion();
- } else if (version == null && (cookie.getPath() != null || cookie.getDomain() != null)) {
- // presence of extended fields makes it version 1 at minimum
- version = 1;
- }
- }
StringBuilder sb = new StringBuilder();
- if (version != null) {
- sb.append("$Version=").append(version.toString());
- quoted = true;
- }
for (Cookie cookie : cookies) {
if (cookie.getName() != null) {
if (sb.length() > 0) {
sb.append("; ");
}
sb.append(cookie.getName()).append('=');
- sb.append(quoted ? HeaderUtil.quote(cookie.getValue()) : cookie.getValue());
- if (cookie.getPath() != null) {
- sb.append("; $Path=").append(HeaderUtil.quote(cookie.getPath()));
- }
- if (cookie.getDomain() != null) {
- sb.append("; $Domain=").append(HeaderUtil.quote(cookie.getDomain()));
- }
- if (cookie.getPort().size() > 0) {
- sb.append("; $Port=").append(HeaderUtil.quote(portList(cookie.getPort())));
- }
- }
- }
- // return null if empty
- return sb.length() > 0 ? singletonList(sb.toString()) : Collections.emptyList();
- }
-
- private String portList(List ports) {
- StringBuilder sb = new StringBuilder();
- for (Integer port : ports) {
- if (sb.length() > 0) {
- sb.append(',');
+ sb.append(HeaderUtil.quote(cookie.getValue()));
}
- sb.append(port.toString());
}
- return sb.toString();
+ return sb.length() > 0 ? singletonList(sb.toString()) : Collections.emptyList();
}
static class Factory extends HeaderFactory {
diff --git a/http-framework/http-core/src/main/java/org/forgerock/http/header/SetCookieHeader.java b/http-framework/http-core/src/main/java/org/forgerock/http/header/SetCookieHeader.java
index b4394e44e..d5b6abd7c 100644
--- a/http-framework/http-core/src/main/java/org/forgerock/http/header/SetCookieHeader.java
+++ b/http-framework/http-core/src/main/java/org/forgerock/http/header/SetCookieHeader.java
@@ -12,16 +12,18 @@
* information: "Portions copyright [year] [name of copyright owner]".
*
* Copyright 2015-2016 ForgeRock AS.
+ * Portions Copyright 2026 Wren Security
*/
package org.forgerock.http.header;
-import static java.util.Collections.*;
+import static java.util.Collections.singletonList;
+import static java.util.Collections.unmodifiableList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-
+import java.util.Map;
import org.forgerock.http.protocol.Cookie;
import org.forgerock.http.protocol.Header;
import org.forgerock.http.protocol.Response;
@@ -52,24 +54,13 @@ public static SetCookieHeader valueOf(String value) {
private static Cookie parseCookie(String value) {
List parts = Arrays.asList(value.split(";"));
- Cookie cookie = new Cookie();
+ Cookie cookie = null;
for (String part : parts) {
String[] nvp = part.split("=", 2);
- if ("Expires".equalsIgnoreCase(nvp[0].trim())) {
- cookie.setExpires(HeaderUtil.parseDate(nvp[1].trim()));
- } else if ("Max-Age".equalsIgnoreCase(nvp[0].trim())) {
- cookie.setMaxAge(parseInteger(nvp[1].trim()));
- } else if ("Path".equalsIgnoreCase(nvp[0].trim())) {
- cookie.setPath(nvp[1]);
- } else if ("Domain".equalsIgnoreCase(nvp[0].trim())) {
- cookie.setDomain(nvp[1]);
- } else if ("Secure".equalsIgnoreCase(nvp[0].trim())) {
- cookie.setSecure(true);
- } else if ("HttpOnly".equalsIgnoreCase(nvp[0].trim())) {
- cookie.setHttpOnly(true);
- } else if (cookie.getName() == null || cookie.getName().isEmpty()) {
- cookie.setName(nvp[0].trim());
- cookie.setValue(nvp[1].trim());
+ if (cookie == null) {
+ cookie = new Cookie(nvp[0].trim(), nvp.length > 1 ? nvp[1].trim() : null);
+ } else {
+ cookie.setAttribute(nvp[0].trim(), nvp.length > 1 ? nvp[1].trim() : Boolean.TRUE.toString());
}
}
if (cookie.getName() == null || cookie.getName().isEmpty()) {
@@ -110,14 +101,6 @@ public static SetCookieHeader valueOf(List values) {
return new SetCookieHeader(unmodifiableList(cookies));
}
- private static Integer parseInteger(String s) {
- try {
- return Integer.valueOf(s);
- } catch (NumberFormatException nfe) {
- return null;
- }
- }
-
private final List cookies;
private final List values;
@@ -161,23 +144,16 @@ private String toString(Cookie cookie) {
StringBuilder sb = new StringBuilder();
if (cookie.getName() != null) {
sb.append(cookie.getName()).append("=").append(cookie.getValue());
- if (cookie.getExpires() != null) {
- sb.append("; ").append("Expires").append("=").append(HeaderUtil.formatDate(cookie.getExpires()));
- }
- if (cookie.getMaxAge() != null ) {
- sb.append("; ").append("Max-Age").append("=").append(cookie.getMaxAge());
- }
- if (cookie.getPath() != null) {
- sb.append("; ").append("Path").append("=").append(cookie.getPath());
- }
- if (cookie.getDomain() != null) {
- sb.append("; ").append("Domain").append("=").append(cookie.getDomain());
- }
- if (cookie.isSecure() != null && cookie.isSecure()) {
- sb.append("; ").append("Secure");
- }
- if (cookie.isHttpOnly() != null && cookie.isHttpOnly()) {
- sb.append("; ").append("HttpOnly");
+ Map attributes = cookie.getAttributes();
+ for (String name : attributes.keySet()) {
+ String value = attributes.get(name);
+ if (value == null) {
+ continue; // unexpected null value (better safe than sorry)
+ } else if (name.equalsIgnoreCase("HttpOnly") || name.equalsIgnoreCase("Secure")) {
+ sb.append("; ").append(name);
+ } else {
+ sb.append("; ").append(name).append("=").append(value);
+ }
}
}
return sb.toString();
diff --git a/http-framework/http-core/src/main/java/org/forgerock/http/protocol/Cookie.java b/http-framework/http-core/src/main/java/org/forgerock/http/protocol/Cookie.java
index 8910d651a..1417e426b 100644
--- a/http-framework/http-core/src/main/java/org/forgerock/http/protocol/Cookie.java
+++ b/http-framework/http-core/src/main/java/org/forgerock/http/protocol/Cookie.java
@@ -13,83 +13,64 @@
*
* Copyright 2010–2011 ApexIdentity Inc.
* Portions Copyright 2011-2015 ForgeRock AS.
+ * Portions Copyright 2026 Wren Security
*/
package org.forgerock.http.protocol;
-import java.util.ArrayList;
+import java.util.Collections;
import java.util.Date;
-import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import org.forgerock.http.header.HeaderUtil;
+import org.wrensecurity.guava.common.base.Objects;
/**
- * An HTTP cookie. For more information, see the original Netscape specification, RFC 2109 and RFC 2965.
+ * An HTTP cookie.
+ *
+ *
+ * For more information see RFC 6265.
*/
public class Cookie {
- /** The name of the cookie. */
- private String name;
- /** The value of the cookie. */
- private String value;
+ private static final String MAX_AGE_ATTR_NAME = "Max-Age";
- /** The intended use of a cookie. */
- private String comment;
+ private static final String EXPIRES_ATTR_NAME = "Expires";
- /** URL identifying the intended use of a cookie. */
- private String commentURL;
+ private static final String DOMAIN_ATTR_NAME = "Domain";
- /**
- * Directs the user agent to discard the cookie unconditionally when it
- * terminates.
- */
- private Boolean discard;
+ private static final String PATH_ATTR_NAME = "Path";
- /** The domain for which the cookie is valid. */
- private String domain;
+ private static final String SECURE_ATTR_NAME = "Secure";
- /**
- * The lifetime of the cookie, expressed as the date and time of expiration.
- */
- private Date expires;
-
- /**
- * Directs the user agent to make the cookie inaccessible to client side
- * script.
- */
- private Boolean httpOnly;
+ private static final String HTTPONLY_ATTR_NAME = "HttpOnly";
- /** The lifetime of the cookie, expressed in seconds. */
- private Integer maxAge;
-
- /** The subset of URLs on the origin server to which this cookie applies. */
- private String path;
+ /** The name of the cookie. */
+ private String name;
- /** Restricts the port(s) to which a cookie may be returned. */
- private final List port = new ArrayList<>();
+ /** The value of the cookie. */
+ private String value;
- /**
- * Directs the user agent to use only secure means to send back this cookie.
- */
- private Boolean secure;
+ /** Additional cookie attribute-value pairs. */
+ private Map attributes;
/**
- * The version of the state management mechanism to which this cookie
- * conforms.
+ * Create a new uninitialized cookie.
*/
- private Integer version;
+ public Cookie() {
+ // Empty cookie.
+ }
/**
- * Creates a new uninitialized cookie.
+ * Create a new cookie with the given name and value.
*/
- public Cookie() {
- // Empty cookie.
+ public Cookie(String name, String value) {
+ this.name = name;
+ this.value = value;
}
@Override
- public boolean equals(final Object obj) {
+ public boolean equals(Object obj) {
if (this == obj) {
return true;
}
@@ -97,379 +78,239 @@ public boolean equals(final Object obj) {
return false;
}
final Cookie other = (Cookie) obj;
- return objectsAreEqual(comment, other.comment)
- && objectsAreEqual(commentURL, other.commentURL)
- && objectsAreEqual(discard, other.discard)
- && objectsAreEqual(domain, other.domain)
- && objectsAreEqual(expires, other.expires)
- && objectsAreEqual(httpOnly, other.httpOnly)
- && objectsAreEqual(maxAge, other.maxAge)
- && objectsAreEqual(name, other.name)
- && objectsAreEqual(path, other.path)
- && objectsAreEqual(port, other.port)
- && objectsAreEqual(secure, other.secure)
- && objectsAreEqual(value, other.value)
- && objectsAreEqual(version, other.version);
+ return Objects.equal(name, other.name)
+ && Objects.equal(value, other.value)
+ && Objects.equal(attributes, other.attributes);
}
- /**
- * Returns the intended use of a cookie.
- *
- * @return The intended use of a cookie.
- */
- public String getComment() {
- return comment;
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name, value, attributes);
}
/**
- * Returns the URL identifying the intended use of a cookie.
+ * Get all cookie attributes.
*
- * @return The URL identifying the intended use of a cookie.
+ * @return cookie attributes or empty map if none defined
*/
- public String getCommentURL() {
- return commentURL;
+ public Map getAttributes() {
+ return attributes == null ? Collections.emptyMap() : Collections.unmodifiableMap(attributes);
}
/**
- * Returns {@code true} if the user agent should discard the cookie
- * unconditionally when it terminates.
+ * Get cookie attribute value.
*
- * @return {@code true} if the user agent should discard the cookie
- * unconditionally when it terminates.
+ * @param name cookie attribute name
+ * @return cookie attribute value or null if no such attribute has been set
*/
- public Boolean getDiscard() {
- return discard;
+ public String getAttribute(String name) {
+ return attributes != null ? attributes.get(name) : null;
}
/**
- * Returns the domain for which the cookie is valid.
+ * Set cookie attribute value or remove existing value by setting null.
*
- * @return The domain for which the cookie is valid.
- */
- public String getDomain() {
- return domain;
- }
-
- /**
- * Returns the lifetime of the cookie, expressed as the date and time of
- * expiration.
+ * @param name cookie attribute name
+ * @param value cookie attribute value to set or null to remove any previously set value
+ * @return this cookie
*
- * @return The lifetime of the cookie, expressed as the date and time of
- * expiration.
+ * @throws IllegalArgumentException in case the attribute name is null or empty
*/
- public Date getExpires() {
- return expires;
- }
+ public Cookie setAttribute(String name, String value) {
+ if (name == null || name.isEmpty()) {
+ throw new IllegalArgumentException("Cookie attribute name can not be empty");
+ }
- /**
- * Returns {@code true} if the user agent should make the cookie
- * inaccessible to client side script.
- *
- * @return {@code true} if the user agent should make the cookie
- * inaccessible to client side script.
- */
- public Boolean isHttpOnly() {
- return httpOnly == null ? false : httpOnly;
+ if (EXPIRES_ATTR_NAME.equalsIgnoreCase(name)) {
+ return setExpires(HeaderUtil.parseDate(value));
+ } else if (MAX_AGE_ATTR_NAME.equalsIgnoreCase(name)) {
+ return setMaxAge(value != null ? parseInteger(value) : null);
+ } else if (HTTPONLY_ATTR_NAME.equalsIgnoreCase(name) || SECURE_ATTR_NAME.equalsIgnoreCase(name)) {
+ return putAttribute(name, Boolean.parseBoolean(value) ? "true" : null);
+ } else {
+ return putAttribute(name, value);
+ }
}
- /**
- * Returns the lifetime of the cookie, expressed in seconds.
- *
- * @return The lifetime of the cookie, expressed in seconds.
- */
- public Integer getMaxAge() {
- return maxAge;
+ private Integer parseInteger(String value) {
+ try {
+ return Integer.parseInt(value);
+ } catch (NumberFormatException e) {
+ return null;
+ }
}
- /**
- * Returns name of the cookie.
- *
- * @return The name of the cookie.
- */
- public String getName() {
- return name;
- }
+ private Cookie putAttribute(String name, String value) {
+ if (attributes == null) {
+ attributes = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ }
- /**
- * Returns the subset of URLs on the origin server to which this cookie
- * applies.
- *
- * @return The subset of URLs on the origin server to which this cookie
- * applies.
- */
- public String getPath() {
- return path;
+ if (value != null) {
+ attributes.put(name, value);
+ } else {
+ attributes.remove(name);
+ }
+ return this;
}
/**
- * Returns the restricted list of port(s) to which a cookie may be returned.
+ * Get name of the cookie.
*
- * @return The restricted list of port(s) to which a cookie may be returned.
+ * @return the name of the cookie
*/
- public List getPort() {
- return port;
+ public String getName() {
+ return name;
}
/**
- * Returns {@code true} if the user agent should use only secure means to
- * send back this cookie.
+ * Set the name of the cookie.
*
- * @return {@code true} if the user agent should use only secure means to
- * send back this cookie.
+ * @param name the name of the cookie
+ * @return this cookie
*/
- public Boolean isSecure() {
- return secure == null ? false : secure;
+ public Cookie setName(String name) {
+ this.name = name;
+ return this;
}
/**
- * Returns the value of the cookie.
+ * Get the value of the cookie.
*
- * @return The value of the cookie.
+ * @return the value of the cookie
*/
public String getValue() {
return value;
}
/**
- * Returns the version of the state management mechanism to which this
- * cookie conforms.
+ * Sets the value of the cookie.
*
- * @return The version of the state management mechanism to which this
- * cookie conforms.
+ * @param value the value of the cookie
+ * @return this cookie
*/
- public Integer getVersion() {
- return version;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + (comment == null ? 0 : comment.hashCode());
- result = prime * result + (commentURL == null ? 0 : commentURL.hashCode());
- result = prime * result + (discard == null ? 0 : discard.hashCode());
- result = prime * result + (domain == null ? 0 : domain.hashCode());
- result = prime * result + (expires == null ? 0 : expires.hashCode());
- result = prime * result + (httpOnly == null ? 0 : httpOnly.hashCode());
- result = prime * result + (maxAge == null ? 0 : maxAge.hashCode());
- result = prime * result + (name == null ? 0 : name.hashCode());
- result = prime * result + (path == null ? 0 : path.hashCode());
- result = prime * result + (port == null ? 0 : port.hashCode());
- result = prime * result + (secure == null ? 0 : secure.hashCode());
- result = prime * result + (value == null ? 0 : value.hashCode());
- result = prime * result + (version == null ? 0 : version.hashCode());
- return result;
+ public Cookie setValue(String value) {
+ this.value = value;
+ return this;
}
/**
- * Sets the intended use of a cookie.
+ * Get the domain for which the cookie is valid.
*
- * @param comment
- * The intended use of a cookie.
- * @return This cookie.
+ * @return the domain for which the cookie is valid
*/
- public Cookie setComment(final String comment) {
- this.comment = comment;
- return this;
+ public String getDomain() {
+ return getAttribute(DOMAIN_ATTR_NAME);
}
/**
- * Sets the URL identifying the intended use of a cookie.
+ * Set the domain for which the cookie is valid.
*
- * @param commentURL
- * The URL identifying the intended use of a cookie.
- * @return This cookie.
+ * @param domain the domain for which the cookie is valid
+ * @return this cookie
*/
- public Cookie setCommentURL(final String commentURL) {
- this.commentURL = commentURL;
- return this;
+ public Cookie setDomain(String domain) {
+ return putAttribute(DOMAIN_ATTR_NAME, domain);
}
/**
- * Sets the value indicating whether the user agent should discard the
- * cookie unconditionally when it terminates.
+ * Get {@code true} if the user agent should make the cookie inaccessible to client side script.
*
- * @param discard
- * {@code true} if the user agent should discard the cookie
- * unconditionally when it terminates.
- * @return This cookie.
+ * @return {@code true} if the user agent should make the cookie inaccessible to client side script.
*/
- public Cookie setDiscard(final Boolean discard) {
- this.discard = discard;
- return this;
+ public Boolean isHttpOnly() {
+ return Boolean.parseBoolean(getAttribute(HTTPONLY_ATTR_NAME));
}
/**
- * Sets the domain for which the cookie is valid.
+ * Set the value indicating whether the user agent should make the cookie inaccessible to client side script.
*
- * @param domain
- * The domain for which the cookie is valid.
- * @return This cookie.
+ * @param httpOnly {@code true} if the user agent should make the cookie inaccessible to client side script
+ * @return this cookie
*/
- public Cookie setDomain(final String domain) {
- this.domain = domain;
- return this;
+ public Cookie setHttpOnly(boolean httpOnly) {
+ return putAttribute(HTTPONLY_ATTR_NAME, httpOnly ? "true" : null);
}
/**
- * Sets the lifetime of the cookie, expressed as the date and time of
- * expiration.
+ * Get the lifetime of the cookie, expressed as the date and time of expiration.
*
- * @param expires
- * The lifetime of the cookie, expressed as the date and time of
- * expiration.
- * @return This cookie.
+ * @return The lifetime of the cookie, expressed as the date and time of expiration.
*/
- public Cookie setExpires(final Date expires) {
- this.expires = expires;
- return this;
+ public Date getExpires() {
+ return HeaderUtil.parseDate(getAttribute(EXPIRES_ATTR_NAME));
}
/**
- * Sets the value indicating whether the user agent should make the cookie
- * inaccessible to client side script.
+ * Set the lifetime of the cookie, expressed as the date and time of expiration.
*
- * @param httpOnly
- * {@code true} if the user agent should make the cookie
- * inaccessible to client side script.
- * @return this;
+ * @param expires the lifetime of the cookie, expressed as the date and time of expiration
+ * @return this cookie
*/
- public Cookie setHttpOnly(final Boolean httpOnly) {
- this.httpOnly = httpOnly;
- return this;
+ public Cookie setExpires(Date expires) {
+ return putAttribute(EXPIRES_ATTR_NAME, expires != null ? HeaderUtil.formatDate(expires) : null);
}
/**
- * Sets the lifetime of the cookie, expressed in seconds.
+ * Get the lifetime of the cookie, expressed in seconds.
*
- * @param maxAge
- * The lifetime of the cookie, expressed in seconds.
- * @return This cookie.
+ * @return the lifetime of the cookie, expressed in seconds
*/
- public Cookie setMaxAge(final Integer maxAge) {
- this.maxAge = maxAge;
- return this;
+ public Integer getMaxAge() {
+ String maxAge = getAttribute(MAX_AGE_ATTR_NAME);
+ return maxAge != null ? Integer.parseInt(maxAge) : null;
}
/**
- * Sets the name of the cookie.
+ * Set the lifetime of the cookie, expressed in seconds.
*
- * @param name
- * The name of the cookie.
- * @return This cookie.
+ * @param maxAge the lifetime of the cookie, expressed in seconds
+ * @return this cookie
*/
- public Cookie setName(final String name) {
- this.name = name;
- return this;
+ public Cookie setMaxAge(Integer maxAge) {
+ return putAttribute(MAX_AGE_ATTR_NAME, maxAge != null ? maxAge.toString() : null);
}
/**
- * Sets the subset of URLs on the origin server to which this cookie
- * applies.
+ * Get the subset of URLs on the origin server to which this cookie applies.
*
- * @param path
- * The subset of URLs on the origin server to which this cookie
- * applies.
- * @return This cookie.
+ * @return the subset of URLs on the origin server to which this cookie applies
*/
- public Cookie setPath(final String path) {
- this.path = path;
- return this;
+ public String getPath() {
+ return getAttribute(PATH_ATTR_NAME);
}
/**
- * Sets the value indicating whether the user agent should use only secure
- * means to send back this cookie.
+ * Set the subset of URLs on the origin server to which this cookie applies.
*
- * @param secure
- * {@code true} if the user agent should use only secure means to
- * send back this cookie.
- * @return This cookie.
+ * @param path the subset of URLs on the origin server to which this cookie applies
+ * @return this cookie
*/
- public Cookie setSecure(final Boolean secure) {
- this.secure = secure;
- return this;
+ public Cookie setPath(String path) {
+ return putAttribute(PATH_ATTR_NAME, path);
}
/**
- * Sets the value of the cookie.
+ * Get flag indicating if the user agent should use only secure means to send back this cookie.
*
- * @param value
- * The value of the cookie.
- * @return This cookie.
+ * @return {@code true} if the user agent should use only secure means to send back this cookie
*/
- public Cookie setValue(final String value) {
- this.value = value;
- return this;
+ public Boolean isSecure() {
+ return Boolean.parseBoolean(getAttribute(SECURE_ATTR_NAME));
}
/**
- * Sets the version of the state management mechanism to which this cookie
- * conforms.
+ * Set the value indicating whether the user agent should use only secure means to send back this cookie.
*
- * @param version
- * The version of the state management mechanism to which this
- * cookie conforms.
- * @return This cookie.
+ * @param secure {@code true} if the user agent should use only secure means to send back this cookie
+ * @return this cookie
*/
- public Cookie setVersion(final Integer version) {
- this.version = version;
- return this;
+ public Cookie setSecure(boolean secure) {
+ return putAttribute(SECURE_ATTR_NAME, secure ? "true" : null);
}
@Override
public String toString() {
- final StringBuilder builder = new StringBuilder();
- builder.append("[");
- if (name != null) {
- builder.append("name=").append(name).append(" ");
- }
- if (value != null) {
- builder.append("value=").append(value).append(" ");
- }
- if (comment != null) {
- builder.append("comment=").append(comment).append(" ");
- }
- if (commentURL != null) {
- builder.append("commentURL=").append(commentURL).append(" ");
- }
- if (discard != null) {
- builder.append("discard=").append(discard).append(" ");
- }
- if (domain != null) {
- builder.append("domain=").append(domain).append(" ");
- }
- if (expires != null) {
- builder.append("expires=").append(expires).append(" ");
- }
- if (httpOnly != null) {
- builder.append("httpOnly=").append(httpOnly).append(" ");
- }
- if (maxAge != null) {
- builder.append("maxAge=").append(maxAge).append(" ");
- }
- if (path != null) {
- builder.append("path=").append(path).append(" ");
- }
- if (port != null) {
- builder.append("port=").append(port).append(" ");
- }
- if (secure != null) {
- builder.append("secure=").append(secure).append(" ");
- }
- if (version != null) {
- builder.append("version=").append(version);
- }
- builder.append("]");
- return builder.toString();
- }
-
- private static boolean objectsAreEqual(final Object o1, final Object o2) {
- if (o1 == null) {
- return o2 == null;
- } else {
- return o1.equals(o2);
- }
+ return String.format("Cookie[%s=%s,%s]", name, value, attributes);
}
}
diff --git a/http-framework/http-core/src/test/java/org/forgerock/http/header/CookieHeaderTest.java b/http-framework/http-core/src/test/java/org/forgerock/http/header/CookieHeaderTest.java
index b4952a0a1..1b5e20f39 100644
--- a/http-framework/http-core/src/test/java/org/forgerock/http/header/CookieHeaderTest.java
+++ b/http-framework/http-core/src/test/java/org/forgerock/http/header/CookieHeaderTest.java
@@ -12,6 +12,7 @@
* information: "Portions Copyright [year] [name of copyright owner]".
*
* Copyright 2014-2016 ForgeRock AS.
+ * Portions Copyright 2026 Wren Security
*/
package org.forgerock.http.header;
@@ -29,9 +30,9 @@
/**
* Unit tests for the cookie header class.
+ *
*