[cpp-sp] branch main updated: Commit new CookieManager sources.
Scott Cantor
cantor.2 at osu.edu
Mon May 5 20:28:43 UTC 2025
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository cpp-sp.
View the commit online:
http://git.shibboleth.net/view/?p=cpp-sp.git;a=commit;h=0ee4b42186cd740bcd293b49cb828801a47fa7f6
The following commit(s) were added to refs/heads/main by this push:
new 0ee4b421 Commit new CookieManager sources.
0ee4b421 is described below
commit 0ee4b42186cd740bcd293b49cb828801a47fa7f6
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon May 5 16:28:39 2025 -0400
Commit new CookieManager sources.
---
shibsp/io/CookieManager.h | 204 +++++++++++++++++++++++++++++++++++++++
shibsp/io/impl/CookieManager.cpp | 170 ++++++++++++++++++++++++++++++++
2 files changed, 374 insertions(+)
diff --git a/shibsp/io/CookieManager.h b/shibsp/io/CookieManager.h
new file mode 100644
index 00000000..afc0de39
--- /dev/null
+++ b/shibsp/io/CookieManager.h
@@ -0,0 +1,204 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file shibsp/util/CookieManager.h
+ *
+ * Manages reading and writing HTTP cookies.
+ */
+
+#ifndef __shibsp_cookiemgr_h__
+#define __shibsp_cookiemgr_h__
+
+#include <shibsp/base.h>
+
+#include <map>
+#include <string>
+
+namespace shibsp {
+
+ class SHIBSP_API SPRequest;
+
+#if defined (_MSC_VER)
+ #pragma warning( push )
+ #pragma warning( disable : 4251 )
+#endif
+
+ /**
+ * HTTP cookie reading and writing helper object.
+ *
+ * <p>This is a thread-safe object that encapsulates some of the older SP's messy handling
+ * of cookie names and properties in various use cases. The name of the cookie managed is
+ * determined by combining various parameters together with the RequestMapper settings
+ * associated with the request provided to the mutating methods.</p>
+ *
+ * <p>The only required input for use of the object is the default cookie name, input
+ * to the constructor. The other settings default to absent, and the default max-age to
+ * -1, indicating a per-session cookie (which in practice are semi-permanent now).</p>
+ */
+ class SHIBSP_API CookieManager
+ {
+ MAKE_NONCOPYABLE(CookieManager);
+ public:
+ /**
+ * Constructor.
+ *
+ * @param default basis for cookie name
+ */
+ CookieManager(const char* defaultName);
+
+ /**
+ * Destructor.
+ */
+ ~CookieManager();
+
+ /** Cookie SameSite values. */
+ enum samesite_t {
+ SAMESITE_ABSENT = 0,
+ SAMESITE_NONE = 1,
+ SAMESITE_LAX = 2,
+ SAMESITE_STRICT = 3
+ };
+
+ /**
+ * Installs controls governing the generation of the name of the cookie managed by this
+ * object.
+ *
+ * <p>If the override property is specified and is present in the request's content
+ * settings, then it will stipulate the exact cookie name to use.</p>
+ *
+ * <p>If no override property is specified, or if the named property is not present in
+ * the request's content settings, then the default name will be used unless modified by
+ * the applicationSpecific flag. If set, the default name will be decorated by adding
+ * a suffix generated from the agent and applicable "applicationId" setting for the request.</p>
+ *
+ * @param overrideProperty name of request/content setting that if present will override
+ * the default cookoe name
+ * @param applicationSpecific whether the default cookie name, if not overridden, should be
+ * decorated so as to be unique to the agent and request's applicationId setting
+ */
+ void setCookieNamePolicy(const char* overrideProperty=nullptr, bool applicationSpecific=false);
+
+ /**
+ * Sets the path attribute for cookies created by this object.
+ *
+ * <p>Defaults to "/".</p>
+ *
+ * @param path path to set
+ */
+ void setPath(const char* path);
+
+ /**
+ * Sets the domain attribute for cookies created by this object.
+ *
+ * <p>Defaults to absent.</p>
+ *
+ * @param domain domain to set
+ */
+ void setDomain(const char* domain);
+
+ /**
+ * Sets the default max-age for cookies created by this object.
+ *
+ * <p>Defaults to -1.</p>
+ *
+ * @param maxAge max-age value
+ */
+ void setMaxAge(int maxAge);
+
+ /**
+ * Sets default Secure attribute for cookies created by this object.
+ *
+ * <p>Defaults to true.</p>
+ *
+ * @param secure value of attribute
+ */
+ void setSecure(bool secure);
+
+ /**
+ * Sets default HttpOnly attribute for cookies created by this object.
+ *
+ * <p>Defaults to true.</p>
+ *
+ * @param httpOnly value of attribute
+ */
+ void setHttpOnly(bool httpOnly);
+
+ /**
+ * Sets default SameSite attribute for cookies created by this object.
+ *
+ * <p>Defaults to absent.</p>
+ *
+ * @param sameSiteValue attribute value
+ */
+ void setSameSite(samesite_t sameSiteValue);
+
+ /**
+ * Adds a cookie with the specified value to the outgoing response for the supplied request.
+ *
+ * <p>The name is determined per the settings configured on this object and the settings
+ * associated with the request.</p>
+ *
+ * <p>The value will NOT be encoded by this method and must be encoded by the caller
+ * if necessary.</p>
+ *
+ * @param request the request to operate on
+ * @param value cookie value
+ */
+ void setCookie(SPRequest& request, const char* value) const;
+
+ /**
+ * Unsets a cookie via the outgoing response for the supplied request.
+ *
+ * <p>The name is determined per the settings configured on this object and the settings
+ * associated with the request.</p>
+ *
+ * @param request the request to operate on
+ */
+ void unsetCookie(SPRequest& request) const;
+
+ /**
+ * Gets the value (if any) for the specified cookie.
+ *
+ * <p>If multiple cookies of the same name are present, it is unspecified
+ * which value will be returned.</p>
+ *
+ * @param request the request to operate on
+ *
+ * @return a value for the named cookie, or nullptr if none exists
+ */
+ const char* getCookieValue(const SPRequest& request) const;
+
+ private:
+ std::string computeCookieName(const SPRequest& request) const;
+ void outputHeader(SPRequest& request, int maxAge) const;
+
+ std::string m_defaultName;
+ std::string m_overrideProperty;
+ bool m_appSpecific;
+ std::string m_path;
+ std::string m_domain;
+ int m_maxAge;
+ bool m_secure;
+ bool m_httpOnly;
+ samesite_t m_sameSiteValue;
+ };
+
+#if defined (_MSC_VER)
+ #pragma warning( pop )
+#endif
+
+};
+
+#endif /* __shibsp_cookiemgr_h__ */
diff --git a/shibsp/io/impl/CookieManager.cpp b/shibsp/io/impl/CookieManager.cpp
new file mode 100644
index 00000000..a1f18080
--- /dev/null
+++ b/shibsp/io/impl/CookieManager.cpp
@@ -0,0 +1,170 @@
+/**
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * io/impl/CookieManager.cpp
+ *
+ * Manages reading and writing HTTP cookies.
+ */
+
+#include "internal.h"
+
+#include "Agent.h"
+#include "SPRequest.h"
+#include "RequestMapper.h"
+#include "io/CookieManager.h"
+#include "util/PropertySet.h"
+
+#include <boost/lexical_cast.hpp>>
+
+using namespace shibsp;
+using namespace std;
+
+CookieManager::CookieManager(const char* defaultName)
+ : m_defaultName(defaultName),
+ m_overrideProperty(nullptr),
+ m_appSpecific(false),
+ m_path("/"),
+ m_maxAge(-1),
+ m_secure(true),
+ m_httpOnly(true),
+ m_sameSiteValue(SAMESITE_ABSENT)
+{
+}
+
+CookieManager::~CookieManager()
+{
+}
+
+void CookieManager::setCookieNamePolicy(const char* overridePropertyName, bool appSpecific)
+{
+ m_overrideProperty = overridePropertyName ? overridePropertyName : nullptr;
+ m_appSpecific = appSpecific;
+}
+
+void CookieManager::setPath(const char* path)
+{
+ m_path = path ? path : "";
+}
+
+void CookieManager::setDomain(const char* domain)
+{
+ m_domain = domain ? domain : "";
+}
+
+void CookieManager::setMaxAge(int maxAge)
+{
+ m_maxAge = maxAge;
+}
+
+void CookieManager::setSecure(bool secure)
+{
+ m_secure = secure;
+}
+
+void CookieManager::setHttpOnly(bool httpOnly)
+{
+ m_httpOnly = httpOnly;
+}
+
+void CookieManager::setSameSite(samesite_t value)
+{
+ m_sameSiteValue = value;
+}
+
+string CookieManager::computeCookieName(const SPRequest& request) const
+{
+ // If not app-specific, return the overridden or default name unadorned.
+ if (!m_appSpecific) {
+ if (m_overrideProperty.empty()) {
+ return m_defaultName;
+ }
+ const char* overridden = request.getRequestSettings().first->getString(m_overrideProperty.c_str());
+ return overridden ? string(overridden) : m_defaultName;
+ }
+
+ // Otherwise, the base name is the default or the overridden name.
+ string cookieName(request.getRequestSettings().first->getString(m_overrideProperty.c_str(), m_defaultName.c_str()));
+
+ // This is just a hex-encode to avoid a dependency on a hashing API.
+ static char DIGITS[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+ string encode(request.getAgent().getID());
+ encode += request.getRequestSettings().first->getString("applicationId", "default");
+ cookieName += '_';
+ for (const char* ch = encode.c_str(); *ch; ++ch) {
+ cookieName += (DIGITS[((unsigned char)(0xF0 & *ch)) >> 4 ]);
+ cookieName += (DIGITS[0x0F & *ch]);
+ }
+
+ return cookieName;
+}
+
+void CookieManager::outputHeader(SPRequest& request, int maxAge) const
+{
+ string header(computeCookieName(request));
+ header += "; max-age=";
+ try {
+ header += boost::lexical_cast<string>(maxAge);
+ }
+ catch (boost::bad_lexical_cast&) {
+ header += "-1";
+ }
+ if (!m_path.empty()) {
+ header += "; path=";
+ header += m_path;
+ }
+ if (!m_domain.empty()) {
+ header += "; domain=";
+ header += m_domain;
+ }
+ if (m_secure) {
+ header += "; secure=1";
+ }
+ if (m_httpOnly) {
+ header += "; HttpOnly=1";
+ }
+ if (m_sameSiteValue != SAMESITE_ABSENT) {
+ switch (m_sameSiteValue) {
+ case SAMESITE_NONE:
+ header += "; SameSite=None";
+ break;
+ case SAMESITE_LAX:
+ header += "; SameSite=Lax";
+ break;
+ case SAMESITE_STRICT:
+ header += "; SameSite=Strict";
+ break;
+ default:
+ }
+ }
+
+ request.setResponseHeader("Set-Cookie", header.c_str());
+}
+
+const char* CookieManager::getCookieValue(const SPRequest& request) const
+{
+ const auto& cookies = request.getCookies();
+ const auto& entry = cookies.find(computeCookieName(request));
+ return entry == cookies.end() ? nullptr : entry->second.c_str();
+}
+
+void CookieManager::setCookie(SPRequest& request, const char* value) const
+{
+ outputHeader(request, request.getRequestSettings().first->getInt("cookieMaxAge", m_maxAge));
+}
+
+void CookieManager::unsetCookie(SPRequest& request) const
+{
+ outputHeader(request, 0);
+}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list