225 lines
10 KiB
Diff
225 lines
10 KiB
Diff
|
|
From 213812355860e3732e1b28e620df31db8ff160aa Mon Sep 17 00:00:00 2001
|
||
|
|
From: Andrew Johnson
|
||
|
|
Date: Mon, 15 Mar 2021 20:53:01 +0530
|
||
|
|
Subject: 569855: Fix for Eclipse live help. - Use tokens - Backport to
|
||
|
|
R4_15_maintenance branch
|
||
|
|
|
||
|
|
Index: eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.base/src/org/eclipse/help/internal/base/BaseHelpSystem.java
|
||
|
|
===================================================================
|
||
|
|
--- eclipse-4.15.orig/eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.base/src/org/eclipse/help/internal/base/BaseHelpSystem.java
|
||
|
|
+++ eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.base/src/org/eclipse/help/internal/base/BaseHelpSystem.java
|
||
|
|
@@ -59,6 +59,7 @@ public final class BaseHelpSystem {
|
||
|
|
private IBrowser browser;
|
||
|
|
private IBrowser internalBrowser;
|
||
|
|
private HelpDisplay helpDisplay = null;
|
||
|
|
+ private String liveHelpToken = null;
|
||
|
|
|
||
|
|
private BaseHelpSystem() {
|
||
|
|
super();
|
||
|
|
@@ -350,4 +351,29 @@ public final class BaseHelpSystem {
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
+ /**
|
||
|
|
+ * Check supplied token against stored token. Clears the stored token if
|
||
|
|
+ * successful.
|
||
|
|
+ *
|
||
|
|
+ * @param helpSessionToken
|
||
|
|
+ * @return true if match successful
|
||
|
|
+ */
|
||
|
|
+ public boolean matchOnceLiveHelpToken(String helpSessionToken) {
|
||
|
|
+ /*
|
||
|
|
+ * @FIXME - should we use a constant time comparison, and store/compare a
|
||
|
|
+ * cryptographic hash?
|
||
|
|
+ */
|
||
|
|
+ if (liveHelpToken != null && liveHelpToken.equals(helpSessionToken)) {
|
||
|
|
+ // Enforce one-time use.
|
||
|
|
+ liveHelpToken = null;
|
||
|
|
+ return true;
|
||
|
|
+ } else {
|
||
|
|
+ return false;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ public void setLiveHelpToken(String helpSessionToken) {
|
||
|
|
+ liveHelpToken = helpSessionToken;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
}
|
||
|
|
Index: eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.base/src/org/eclipse/help/internal/base/HelpDisplay.java
|
||
|
|
===================================================================
|
||
|
|
--- eclipse-4.15.orig/eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.base/src/org/eclipse/help/internal/base/HelpDisplay.java
|
||
|
|
+++ eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.base/src/org/eclipse/help/internal/base/HelpDisplay.java
|
||
|
|
@@ -15,6 +15,8 @@ package org.eclipse.help.internal.base;
|
||
|
|
|
||
|
|
import java.io.UnsupportedEncodingException;
|
||
|
|
import java.net.URLEncoder;
|
||
|
|
+import java.nio.charset.StandardCharsets;
|
||
|
|
+import java.util.UUID;
|
||
|
|
|
||
|
|
import org.eclipse.core.runtime.CoreException;
|
||
|
|
import org.eclipse.core.runtime.IConfigurationElement;
|
||
|
|
@@ -196,6 +198,12 @@ public class HelpDisplay {
|
||
|
|
String topic = helpURL.substring("topic=".length()); //$NON-NLS-1$
|
||
|
|
helpURL = getHelpDisplay().getHelpForTopic( topic, WebappManager.getHost(), WebappManager.getPort());
|
||
|
|
}
|
||
|
|
+ String basehelp = getBaseURL();
|
||
|
|
+ if (BaseHelpSystem.getMode() != BaseHelpSystem.MODE_INFOCENTER && helpURL.startsWith(basehelp)) {
|
||
|
|
+ String sessid = UUID.randomUUID().toString();
|
||
|
|
+ BaseHelpSystem.getInstance().setLiveHelpToken(sessid);
|
||
|
|
+ helpURL += (helpURL.indexOf('?') < 0 ? '?' : '&') + "token=" + sessid; //$NON-NLS-1$
|
||
|
|
+ }
|
||
|
|
|
||
|
|
BaseHelpSystem.getHelpBrowser(forceExternal)
|
||
|
|
.displayURL(helpURL);
|
||
|
|
Index: eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/advanced/livehelp_js.jsp
|
||
|
|
===================================================================
|
||
|
|
--- eclipse-4.15.orig/eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/advanced/livehelp_js.jsp
|
||
|
|
+++ eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/advanced/livehelp_js.jsp
|
||
|
|
@@ -47,7 +47,15 @@ function liveActionInternal(topHelpWindo
|
||
|
|
url=url.substring(0, i+1);
|
||
|
|
var encodedArg=encodeURIComponent(argument);
|
||
|
|
url=url+"livehelp/?pluginID="+pluginId+"&class="+className+"&arg="+encodedArg+"&nocaching="+Math.random();
|
||
|
|
-
|
||
|
|
+ <%
|
||
|
|
+ Object token = request.getSession().getAttribute("LSESSION"); //$NON-NLS-1$
|
||
|
|
+ // Validate token to protect against XSS
|
||
|
|
+ if (token instanceof String && ((String)token).matches("[a-z0-9-]{36}")) {//$NON-NLS-1$) {
|
||
|
|
+ %>
|
||
|
|
+ url=url+"&token=<%=token%>";
|
||
|
|
+ <%
|
||
|
|
+ }
|
||
|
|
+ %>
|
||
|
|
// we need to find the toolbar frame.
|
||
|
|
// to do: cleanup this, including the location of the hidden livehelp frame.
|
||
|
|
var toolbarFrame = topHelpWindow.HelpFrame.ContentFrame.ContentToolbarFrame;
|
||
|
|
Index: eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/index.jsp
|
||
|
|
===================================================================
|
||
|
|
--- eclipse-4.15.orig/eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/index.jsp
|
||
|
|
+++ eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/index.jsp
|
||
|
|
@@ -12,9 +12,11 @@
|
||
|
|
IBM Corporation - initial API and implementation
|
||
|
|
--%>
|
||
|
|
<%@ page import="org.eclipse.help.internal.webapp.data.*" errorPage="/advanced/err.jsp" contentType="text/html; charset=UTF-8"%>
|
||
|
|
+<%@ page import="java.util.UUID" %>
|
||
|
|
+<%@ page import="org.eclipse.help.internal.base.BaseHelpSystem" %>
|
||
|
|
<%
|
||
|
|
request.setCharacterEncoding("UTF-8");
|
||
|
|
- ServerState.webappStarted(application,request, response);
|
||
|
|
+ ServerState.webappStarted(application,request, response);
|
||
|
|
// Read the scope parameter
|
||
|
|
RequestScope.setScopeFromRequest(request, response);
|
||
|
|
LayoutData data = new LayoutData(application,request, response);
|
||
|
|
@@ -33,7 +35,22 @@
|
||
|
|
</body>
|
||
|
|
</html>
|
||
|
|
<%
|
||
|
|
- }else {
|
||
|
|
+ } else {
|
||
|
|
+ // For live help
|
||
|
|
+ String token = request.getParameter("token"); //$NON-NLS-1$
|
||
|
|
+ if (token != null && token.matches("[a-z0-9-]{36}")) { //$NON-NLS-1$
|
||
|
|
+ if (BaseHelpSystem.getInstance().matchOnceLiveHelpToken(token)) {
|
||
|
|
+ // Only one session can grab this
|
||
|
|
+ if (request.getSession().getAttribute("XSESSION") == null) { //$NON-NLS-1$
|
||
|
|
+ String token2 = UUID.randomUUID().toString();
|
||
|
|
+ request.getSession().setAttribute("XSESSION", token2); //$NON-NLS-1$
|
||
|
|
+ int port = request.getLocalPort();
|
||
|
|
+ response.addHeader("Set-Cookie", "XSESSION-" + port + "=" + token2 + "; HttpOnly; SameSite=Strict"); //$NON-NLS-1 //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
|
||
|
|
+ String token3 = UUID.randomUUID().toString();
|
||
|
|
+ request.getSession().setAttribute("LSESSION", token3); //$NON-NLS-1$
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
request.getRequestDispatcher("/advanced/index.jsp" + data.getQuery()).forward(request, response);
|
||
|
|
}
|
||
|
|
%>
|
||
|
|
Index: eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/src/org/eclipse/help/internal/webapp/data/LayoutData.java
|
||
|
|
===================================================================
|
||
|
|
--- eclipse-4.15.orig/eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/src/org/eclipse/help/internal/webapp/data/LayoutData.java
|
||
|
|
+++ eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/src/org/eclipse/help/internal/webapp/data/LayoutData.java
|
||
|
|
@@ -46,6 +46,11 @@ public class LayoutData extends RequestD
|
||
|
|
|
||
|
|
// initialize the query string
|
||
|
|
String qs = request.getQueryString();
|
||
|
|
+ // Remove any live help token
|
||
|
|
+ if (qs != null) {
|
||
|
|
+ qs = qs.replaceFirst("^token=[a-z0-9-]{36}", ""); //$NON-NLS-1$ //$NON-NLS-2$
|
||
|
|
+ qs = qs.replaceFirst("&token=[a-z0-9-]{36}", ""); //$NON-NLS-1$ //$NON-NLS-2$
|
||
|
|
+ }
|
||
|
|
if (qs != null && qs.length() > 0)
|
||
|
|
query = "?" + qs; //$NON-NLS-1$
|
||
|
|
}
|
||
|
|
Index: eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/src/org/eclipse/help/internal/webapp/servlet/LiveHelpServlet.java
|
||
|
|
===================================================================
|
||
|
|
--- eclipse-4.15.orig/eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/src/org/eclipse/help/internal/webapp/servlet/LiveHelpServlet.java
|
||
|
|
+++ eclipse-platform-sources-I20200305-0155/eclipse.platform.ua/org.eclipse.help.webapp/src/org/eclipse/help/internal/webapp/servlet/LiveHelpServlet.java
|
||
|
|
@@ -14,8 +14,8 @@
|
||
|
|
package org.eclipse.help.internal.webapp.servlet;
|
||
|
|
|
||
|
|
import java.io.IOException;
|
||
|
|
-
|
||
|
|
import javax.servlet.ServletException;
|
||
|
|
+import javax.servlet.http.Cookie;
|
||
|
|
import javax.servlet.http.HttpServlet;
|
||
|
|
import javax.servlet.http.HttpServletRequest;
|
||
|
|
import javax.servlet.http.HttpServletResponse;
|
||
|
|
@@ -51,6 +51,45 @@ public class LiveHelpServlet extends Htt
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
req.setCharacterEncoding("UTF-8"); //$NON-NLS-1$
|
||
|
|
+ String sessionid = req.getSession().getId();
|
||
|
|
+ Cookie cookies[] = req.getCookies();
|
||
|
|
+ boolean jsessOK = false;
|
||
|
|
+ boolean xsessOK = false;
|
||
|
|
+ boolean lsessOK = false;
|
||
|
|
+ // Unique session ID per help server
|
||
|
|
+ int port = req.getLocalPort();
|
||
|
|
+ String xsessname = "XSESSION-" + port; //$NON-NLS-1$
|
||
|
|
+ if (cookies != null) {
|
||
|
|
+ for (Cookie cookie : cookies) {
|
||
|
|
+ if (cookie.getName().equals("JSESSIONID")) {//$NON-NLS-1$
|
||
|
|
+ if (sessionid.length() >= 30 &&
|
||
|
|
+ cookie.getValue().startsWith(sessionid)) {
|
||
|
|
+ jsessOK = true;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ if (cookie.getName().equals(xsessname)) {
|
||
|
|
+ if (cookie.getValue().equals(req.getSession().getAttribute("XSESSION"))) { //$NON-NLS-1$
|
||
|
|
+ xsessOK = true;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ String token = req.getParameter("token"); //$NON-NLS-1$
|
||
|
|
+ if (token != null && token.equals(req.getSession().getAttribute("LSESSION"))) { //$NON-NLS-1$
|
||
|
|
+ lsessOK = true;
|
||
|
|
+ }
|
||
|
|
+ if (!jsessOK) {
|
||
|
|
+ resp.sendError(HttpServletResponse.SC_FORBIDDEN, "JSESSIONID"); //$NON-NLS-1$
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+ if (!lsessOK) {
|
||
|
|
+ resp.sendError(HttpServletResponse.SC_FORBIDDEN, "token"); //$NON-NLS-1$
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+ if (!xsessOK) {
|
||
|
|
+ resp.sendError(HttpServletResponse.SC_FORBIDDEN, xsessname);
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
String pluginID = req.getParameter("pluginID"); //$NON-NLS-1$
|
||
|
|
if (pluginID == null)
|
||
|
|
return;
|
||
|
|
@@ -59,6 +98,11 @@ public class LiveHelpServlet extends Htt
|
||
|
|
return;
|
||
|
|
String arg = req.getParameter("arg"); //$NON-NLS-1$
|
||
|
|
BaseHelpSystem.runLiveHelp(pluginID, className, arg);
|
||
|
|
+ /*
|
||
|
|
+ * @FIXME Should runLiveHelp return an error if the plugin/class is wrong
|
||
|
|
+ * so a SC_BAD_REQUEST can be returned? Or does this reveal too much?
|
||
|
|
+ */
|
||
|
|
+ resp.setStatus(HttpServletResponse.SC_ACCEPTED);
|
||
|
|
}
|
||
|
|
/**
|
||
|
|
*
|