From 2593292e3694752ffff1b6f365328b834cae0b14 Mon Sep 17 00:00:00 2001 From: brianbrix Date: Mon, 15 Jun 2026 19:29:43 +0300 Subject: [PATCH 01/23] AMP-31141 : Re-enable and redesign CSRF protection for state-changing web flows except rest(next) --- .../digijava/kernel/taglib/html/FormTag.java | 27 ++++ .../webapp/WEB-INF/applicationContext.xml | 12 +- .../dynLocationManager/dynLocationManager.jsp | 3 + .../WEB-INF/jsp/aim/view/luceneIndex.jsp | 1 + .../WEB-INF/jsp/aim/view/scripts/common.js | 115 ++++++++++++++++++ .../view/doctabmanager/docTabManager.jsp | 7 +- .../view/labelmanager/labelManager.jsp | 2 + .../WEB-INF/jsp/translate/view/addkey.jsp | 1 + .../jsp/translate/view/globaladdkey.jsp | 1 + .../jsp/translate/view/globaltranslation.jsp | 1 + .../jsp/translate/view/translation.jsp | 1 + .../main/webapp/WEB-INF/jsp/um/view/reset.jsp | 3 +- 12 files changed, 167 insertions(+), 7 deletions(-) diff --git a/amp/src/main/java/org/digijava/kernel/taglib/html/FormTag.java b/amp/src/main/java/org/digijava/kernel/taglib/html/FormTag.java index a5003eca476..331794290d6 100644 --- a/amp/src/main/java/org/digijava/kernel/taglib/html/FormTag.java +++ b/amp/src/main/java/org/digijava/kernel/taglib/html/FormTag.java @@ -22,6 +22,7 @@ package org.digijava.kernel.taglib.html; +import org.apache.commons.lang.StringEscapeUtils; import org.apache.struts.taglib.TagUtils; import org.apache.struts.taglib.html.Constants; import org.digijava.kernel.request.Site; @@ -31,6 +32,7 @@ import org.digijava.kernel.util.SiteCache; import org.digijava.kernel.util.SiteConfigUtils; import org.digijava.kernel.util.SiteUtils; +import org.springframework.security.web.csrf.CsrfToken; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -161,6 +163,7 @@ public int doStartTag() throws JspException { results.append(this.renderFormStart()); results.append(renderToken()); + results.append(renderSpringCsrfToken(request)); TagUtils.getInstance().write(pageContext, results.toString()); @@ -286,6 +289,30 @@ protected String renderFormStart() throws JspException { return results.toString(); } + protected String renderSpringCsrfToken(HttpServletRequest request) { + if (isSafeMethod()) { + return ""; + } + + CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName()); + if (csrfToken == null) { + return ""; + } + + return ""; + } + + private boolean isSafeMethod() { + return "get".equalsIgnoreCase(method) + || "head".equalsIgnoreCase(method) + || "options".equalsIgnoreCase(method) + || "trace".equalsIgnoreCase(method); + } + /** * Release any acquired resources. */ diff --git a/amp/src/main/webapp/WEB-INF/applicationContext.xml b/amp/src/main/webapp/WEB-INF/applicationContext.xml index 451b5dc129d..30bc74892be 100644 --- a/amp/src/main/webapp/WEB-INF/applicationContext.xml +++ b/amp/src/main/webapp/WEB-INF/applicationContext.xml @@ -18,6 +18,8 @@ + + @@ -201,22 +203,22 @@ - + - + - + - + @@ -250,7 +252,7 @@ - + diff --git a/amp/src/main/webapp/WEB-INF/jsp/aim/view/dynLocationManager/dynLocationManager.jsp b/amp/src/main/webapp/WEB-INF/jsp/aim/view/dynLocationManager/dynLocationManager.jsp index e9cfd4b077a..14e86fa2e66 100644 --- a/amp/src/main/webapp/WEB-INF/jsp/aim/view/dynLocationManager/dynLocationManager.jsp +++ b/amp/src/main/webapp/WEB-INF/jsp/aim/view/dynLocationManager/dynLocationManager.jsp @@ -331,6 +331,7 @@
+ @@ -339,6 +340,7 @@
+ @@ -346,6 +348,7 @@
+
diff --git a/amp/src/main/webapp/WEB-INF/jsp/aim/view/luceneIndex.jsp b/amp/src/main/webapp/WEB-INF/jsp/aim/view/luceneIndex.jsp index 0809f35a2be..0420bd84264 100644 --- a/amp/src/main/webapp/WEB-INF/jsp/aim/view/luceneIndex.jsp +++ b/amp/src/main/webapp/WEB-INF/jsp/aim/view/luceneIndex.jsp @@ -71,6 +71,7 @@
+ Field: String: diff --git a/amp/src/main/webapp/WEB-INF/jsp/aim/view/scripts/common.js b/amp/src/main/webapp/WEB-INF/jsp/aim/view/scripts/common.js index 006916c4157..faf323bdbeb 100644 --- a/amp/src/main/webapp/WEB-INF/jsp/aim/view/scripts/common.js +++ b/amp/src/main/webapp/WEB-INF/jsp/aim/view/scripts/common.js @@ -1,6 +1,121 @@ function unload() { } + (function () { + var CSRF_COOKIE = "XSRF-TOKEN"; + var CSRF_HEADER = "X-XSRF-TOKEN"; + var CSRF_PARAMETER = "_csrf"; + + function getCookie(name) { + var namePrefix = name + "="; + var cookies = document.cookie ? document.cookie.split(";") : []; + for (var index = 0; index < cookies.length; index++) { + var cookie = cookies[index].replace(/^\s+|\s+$/g, ""); + if (cookie.indexOf(namePrefix) === 0) { + return decodeURIComponent(cookie.substring(namePrefix.length)); + } + } + return null; + } + + function getCsrfToken() { + return getCookie(CSRF_COOKIE); + } + + function isUnsafeMethod(method) { + var normalizedMethod = (method || "GET").toUpperCase(); + return normalizedMethod !== "GET" && normalizedMethod !== "HEAD" + && normalizedMethod !== "OPTIONS" && normalizedMethod !== "TRACE"; + } + + function isSameOrigin(url) { + if (!url || (url.charAt(0) === "/" && url.charAt(1) !== "/")) { + return true; + } + if (url.indexOf("http://") !== 0 && url.indexOf("https://") !== 0 && url.indexOf("//") !== 0) { + return true; + } + + var anchor = document.createElement("a"); + anchor.href = url; + return anchor.protocol === window.location.protocol && anchor.host === window.location.host; + } + + function addCsrfToForm(form) { + var token = getCsrfToken(); + if (!token || !form || !isUnsafeMethod(form.method) || !isSameOrigin(form.action)) { + return; + } + + var tokenInput = form.elements[CSRF_PARAMETER]; + if (!tokenInput) { + tokenInput = document.createElement("input"); + tokenInput.type = "hidden"; + tokenInput.name = CSRF_PARAMETER; + form.appendChild(tokenInput); + } + tokenInput.value = token; + } + + if (document.addEventListener) { + document.addEventListener("submit", function (event) { + addCsrfToForm(event.target); + }, true); + } else if (document.attachEvent) { + document.attachEvent("onsubmit", function () { + addCsrfToForm(window.event.srcElement); + }); + } + + if (window.XMLHttpRequest && window.XMLHttpRequest.prototype) { + var originalOpen = window.XMLHttpRequest.prototype.open; + var originalSend = window.XMLHttpRequest.prototype.send; + + window.XMLHttpRequest.prototype.open = function (method, url) { + this.ampCsrfMethod = method; + this.ampCsrfUrl = url; + return originalOpen.apply(this, arguments); + }; + + window.XMLHttpRequest.prototype.send = function () { + var token = getCsrfToken(); + if (token && isUnsafeMethod(this.ampCsrfMethod) && isSameOrigin(this.ampCsrfUrl)) { + try { + this.setRequestHeader(CSRF_HEADER, token); + } catch (ignored) { + } + } + return originalSend.apply(this, arguments); + }; + } + + if (window.fetch) { + var originalFetch = window.fetch; + window.fetch = function (input, init) { + var options = init || {}; + var method = options.method || (input && input.method) || "GET"; + var url = typeof input === "string" ? input : (input && input.url); + var token = getCsrfToken(); + + if (token && isUnsafeMethod(method) && isSameOrigin(url)) { + options = init || {}; + if (window.Headers && options.headers instanceof window.Headers) { + options.headers = new window.Headers(options.headers); + options.headers.set(CSRF_HEADER, token); + } else if (Object.prototype.toString.call(options.headers) === "[object Array]") { + options.headers.push([CSRF_HEADER, token]); + } else { + options.headers = options.headers || {}; + options.headers[CSRF_HEADER] = token; + } + return originalFetch.call(this, input, options); + } + + return originalFetch.apply(this, arguments); + }; + } + }()); + if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { diff --git a/amp/src/main/webapp/WEB-INF/jsp/contentrepository/view/doctabmanager/docTabManager.jsp b/amp/src/main/webapp/WEB-INF/jsp/contentrepository/view/doctabmanager/docTabManager.jsp index 19f5307f5d0..4e450e8db0e 100644 --- a/amp/src/main/webapp/WEB-INF/jsp/contentrepository/view/doctabmanager/docTabManager.jsp +++ b/amp/src/main/webapp/WEB-INF/jsp/contentrepository/view/doctabmanager/docTabManager.jsp @@ -133,6 +133,11 @@ var trnObj = { function retrieveFilterData(filterId) { YAHOO.util.Connect.asyncRequest('GET', '/contentrepository/publicDocTabManager.do?time='+ new Date().getTime()+'&action=jsonfilter&filterId='+filterId, new RetrieveFilters(publicListObj) ); } + + function deleteFilter(filterId) { + document.forms["crDocTabManagerForm"].action = "/contentrepository/publicDocTabManager.do?action=delete&filterId=" + filterId; + document.forms["crDocTabManagerForm"].submit(); + } YAHOO.util.Event.on(window, "load", afterPageLoad); @@ -253,7 +258,7 @@ var trnObj = { ${filter.name} [Delete] + href="#" onclick="deleteFilter(${filter.id}); return false;">Delete] diff --git a/amp/src/main/webapp/WEB-INF/jsp/contentrepository/view/labelmanager/labelManager.jsp b/amp/src/main/webapp/WEB-INF/jsp/contentrepository/view/labelmanager/labelManager.jsp index becd717961c..08198990101 100644 --- a/amp/src/main/webapp/WEB-INF/jsp/contentrepository/view/labelmanager/labelManager.jsp +++ b/amp/src/main/webapp/WEB-INF/jsp/contentrepository/view/labelmanager/labelManager.jsp @@ -258,6 +258,7 @@