You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by de...@apache.org on 2016/12/09 16:12:53 UTC

svn commit: r1773423 - in /uima/uima-ducc/trunk: src/main/resources/ uima-ducc-common/src/main/java/org/apache/uima/ducc/common/utils/ uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/ uima-ducc-web/src/main/webapp/etc/

Author: degenaro
Date: Fri Dec  9 16:12:53 2016
New Revision: 1773423

URL: http://svn.apache.org/viewvc?rev=1773423&view=rev
Log:
UIMA-5206 DUCC Web Server (WS) should provide restriction on responses comprising user data

Added:
    uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandlerHttpRequestFilter.java   (with props)
    uima/uima-ducc/trunk/uima-ducc-web/src/main/webapp/etc/http-uri-encryption-exemption.list
Modified:
    uima/uima-ducc/trunk/src/main/resources/default.ducc.properties
    uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/utils/DuccPropertiesResolver.java
    uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccWebServer.java

Modified: uima/uima-ducc/trunk/src/main/resources/default.ducc.properties
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/src/main/resources/default.ducc.properties?rev=1773423&r1=1773422&r2=1773423&view=diff
==============================================================================
--- uima/uima-ducc/trunk/src/main/resources/default.ducc.properties (original)
+++ uima/uima-ducc/trunk/src/main/resources/default.ducc.properties Fri Dec  9 16:12:53 2016
@@ -306,6 +306,13 @@ ducc.ws.visualization.strip.domain = tru
 # Logs are written to DUCC_HOME/logs/webserver
 ducc.ws.requestLog.RetainDays = 30
 
+# Specify one of { unrestricted, encrypted, blocked } to control 
+# requests to the Web Server with responses containing user data. 
+# When "unrestricted" requests for user data via http or https are honored.
+# When "encrypted" requests for user data only via https are honored.
+# When "blocked" requests for user data are not honored.
+ducc.ws.user.data.access = unrestricted
+
 # --------------------------------------------------------------
 #    name: ducc.ws.banner.message
 # purpose: display banner message on all main pages

Modified: uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/utils/DuccPropertiesResolver.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/utils/DuccPropertiesResolver.java?rev=1773423&r1=1773422&r2=1773423&view=diff
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/utils/DuccPropertiesResolver.java (original)
+++ uima/uima-ducc/trunk/uima-ducc-common/src/main/java/org/apache/uima/ducc/common/utils/DuccPropertiesResolver.java Fri Dec  9 16:12:53 2016
@@ -163,6 +163,7 @@ public class DuccPropertiesResolver {
     public static final String ducc_ws_login_enabled = "ducc.ws.login.enabled";
     public static final String ducc_ws_bytes_per_page = "ducc.ws.bytes.per.page";
     public static final String ducc_ws_banner_message = "ducc.ws.banner.message";
+    public static final String ducc_ws_user_data_access = "ducc.ws.user.data.access";
     
     public static final String ducc_rm_node_stability = "ducc.rm.node.stability";
     public static final String ducc_agent_node_metrics_publish_rate = "ducc.agent.node.metrics.publish.rate";

Added: uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandlerHttpRequestFilter.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandlerHttpRequestFilter.java?rev=1773423&view=auto
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandlerHttpRequestFilter.java (added)
+++ uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandlerHttpRequestFilter.java Fri Dec  9 16:12:53 2016
@@ -0,0 +1,335 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+*/
+package org.apache.uima.ducc.ws.server;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.uima.ducc.common.IDuccEnv;
+import org.apache.uima.ducc.common.utils.DuccLogger;
+import org.apache.uima.ducc.common.utils.DuccLoggerComponents;
+import org.apache.uima.ducc.common.utils.DuccPropertiesResolver;
+import org.apache.uima.ducc.common.utils.id.DuccId;
+import org.apache.uima.ducc.ws.server.DuccWebServer.ConfigValue;
+import org.eclipse.jetty.server.Request;
+
+public class DuccHandlerHttpRequestFilter extends DuccAbstractHandler {
+	
+	private static DuccLogger duccLogger = DuccLoggerComponents.getWsLogger(DuccHandlerHttpRequestFilter.class.getName());
+	private static volatile DuccId jobid = null;
+	
+	// refresh interval for both ducc.properties and URI encryption exception list
+	private long expiryMillis = 60*1000;
+	
+	// TOD of last refresh
+	private AtomicLong saveMillisUpdate = new AtomicLong(0);
+	
+	// valid values for ducc.ws.user.data.access
+	private enum UserDataAccessMode { unrestricted, encrypted, blocked };
+	
+	// present value of ducc.ws.user.data.access
+	private volatile UserDataAccessMode userDataAccessMode = UserDataAccessMode.unrestricted;
+	
+	// present list of encryption exempt URI prefixes
+	private volatile List<String> listEncryptionException = new ArrayList<String>();
+	
+	// file containing list of encryption exempt URI prefixes
+	// - one per line
+	// - comments start with #
+	private String filePath = IDuccEnv.DUCC_HOME_DIR
+					+File.separator
+					+"webserver"
+					+File.separator
+					+"etc"
+					+File.separator
+					+"http-uri-encryption-exemption.list"
+					;
+	
+	public DuccHandlerHttpRequestFilter(DuccWebServer duccWebServer) {
+		super.init(duccWebServer);
+	}
+	
+	// re-read file containing list of encryption exempt URI prefixes
+	private void refreshListEncryptionException() {
+		String location = "refreshListEncryptionException";
+		try {
+			List<String> listRefresh = new ArrayList<String>();
+			BufferedReader br = null;
+	        try {
+	            br = new BufferedReader(new FileReader(filePath));
+	            String line;
+	            while ((line = br.readLine()) != null) {
+	                line = line.trim();
+	                if(line.startsWith("#")) {
+	                	continue;
+	                }
+	                if(line.length() > 0) {
+	                	listRefresh.add(line);
+	                }
+	            }
+	            listEncryptionException = listRefresh;
+	        } 
+	        catch (IOException e) {
+	        	duccLogger.trace(location, jobid, e);
+	        } 
+	        finally {
+	            try {
+	                if (br != null) {
+	                    br.close();
+	                }
+	            } 
+	            catch (IOException e) {
+	            	duccLogger.error(location, jobid, e);
+	            }
+	        }
+	        duccLogger.debug(location, jobid, "size:"+listEncryptionException.size());
+		}
+		catch (Exception e) {
+        	duccLogger.error(location, jobid, e);
+        }
+	}
+	
+	private List<String> getListEncryptionException() {
+		return listEncryptionException;
+	}
+	
+	// re-read value of ducc.ws.user.data.access
+	private void refreshUserDataAccessMode() {
+		String location = "refreshUserDataAccessMode";
+		try {
+			DuccPropertiesResolver dpr = DuccPropertiesResolver.getInstance();
+			String property = dpr.getFileProperty(DuccPropertiesResolver.ducc_ws_user_data_access);
+			if(property != null) {
+				property = property.trim();
+				if(property.equals(UserDataAccessMode.unrestricted.name())) {
+					userDataAccessMode = UserDataAccessMode.unrestricted;
+				}
+				else if(property.equals(UserDataAccessMode.encrypted.name())) {
+					userDataAccessMode = UserDataAccessMode.encrypted;
+				}
+				else if(property.equals(UserDataAccessMode.blocked.name())) {
+					userDataAccessMode = UserDataAccessMode.blocked;
+				}
+				else {
+					String message = "no change, unrecognized value: "+property;
+					duccLogger.warn(location, jobid, message);
+				}
+			}
+			else {
+				userDataAccessMode = UserDataAccessMode.unrestricted;
+			}
+		}
+		catch(Exception e) {
+			duccLogger.error(location, jobid, e);
+		}
+	}
+
+	private UserDataAccessMode getUserDataAccessMode() {
+		return userDataAccessMode;
+	}
+	
+	private boolean isRestrictedHttp() {
+		boolean retVal = false;
+		UserDataAccessMode uda = getUserDataAccessMode();
+		switch(uda) {
+		default:
+		case unrestricted:
+			break;
+		case encrypted:
+		case blocked:
+			retVal = true;
+		}
+		return retVal;
+	}
+	
+	private boolean isRestrictedHttps() {
+		boolean retVal = false;
+		UserDataAccessMode uda = getUserDataAccessMode();
+		switch(uda) {
+		default:
+		case unrestricted:
+		case encrypted:
+			break;
+		case blocked:
+			retVal = true;
+		}
+		return retVal;
+	}
+	
+	// check if request scheme is restricted
+	private boolean isRestrictedScheme(String scheme) {
+		boolean retVal = false;
+		if(scheme.equals("http")) {
+			retVal = isRestrictedHttp();
+		}
+		else if(scheme.equals("https")) {
+			retVal = isRestrictedHttps();
+		}
+		return retVal;
+	}
+	
+	// if refresh time has elapsed, refresh ducc property and encryption exception list
+	private void refresh() {
+		long timeMillisNow = System.currentTimeMillis();
+		long timeMillisLastUpdate = saveMillisUpdate.get();
+		if(timeMillisNow-timeMillisLastUpdate > expiryMillis) {
+			refreshUserDataAccessMode();
+			refreshListEncryptionException();
+			saveMillisUpdate.set(timeMillisNow);
+		}
+	}
+	
+	private String getContentForbiddenPage() {
+		StringBuffer sb = new StringBuffer();
+		sb.append("<html>");
+		sb.append("<body>");
+		sb.append("<p>");
+		sb.append("Forbidden.");
+		sb.append("</p>");
+		sb.append("</body>");
+		sb.append("</html>");
+		return sb.toString();
+	}
+	
+	private boolean isRestrictedUri(String reqUri) {
+		boolean retVal = true;
+		List<String> list = getListEncryptionException();
+		for(String includeUri : list) {
+			if(reqUri.startsWith(includeUri)) {
+				retVal = false;
+				break;
+			}
+		}
+		return retVal;
+	}
+	
+	// forbid http for mode "encrypted" & "blocked"
+	// forbid https for mode "blocked"
+	public void handleForbidden(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
+		String location = "handleForbidden";
+		if(!baseRequest.isHandled()) {
+			String scheme = request.getScheme();
+			if(isRestrictedScheme(scheme)) {
+				String reqUri = request.getRequestURI();
+				if(isRestrictedUri(reqUri)) {
+					String content = getContentForbiddenPage();
+					response.getWriter().println(content);
+					StringBuffer sb = new StringBuffer();
+					sb.append("forbidden:"+" "+reqUri);
+					duccLogger.info(location, jobid, sb);
+					response.setContentType("text/html;charset=utf-8");
+					response.setStatus(HttpServletResponse.SC_FORBIDDEN);
+					baseRequest.setHandled(true);
+					DuccWebUtil.noCache(response);
+				}
+			}
+		}
+	}
+	
+	private String getContentRedirect(String url) {
+		StringBuffer sb = new StringBuffer();
+		sb.append("<html>");
+		sb.append("<head>");
+		sb.append("<script type=\"text/javascript\">");
+		sb.append(" window.location.href = \""+url+"\"");
+		sb.append("</script>");
+		sb.append("</head>");
+		sb.append("<body>");
+		sb.append("Redirecting to ");
+		sb.append("<a href='"+url+"'>"+url+"</a>");
+		sb.append("</body>");
+		sb.append("</html>");
+		return sb.toString();
+	}
+	
+	// redirect http to https when possible for mode "encrypted"
+	public void handleRedirect(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
+		String location = "handleRedirect";
+		if(!baseRequest.isHandled()) {
+			UserDataAccessMode uda = getUserDataAccessMode();
+			switch(uda) {
+			case encrypted:
+				String scheme = request.getScheme();
+				if(scheme.equals("http")) {
+					String reqUri = request.getRequestURI();
+					if(isRestrictedUri(reqUri)) {
+						String url = request.getRequestURL().toString();
+				        String portHttps = ""+ConfigValue.PortHttps.getInt(DuccPropertiesResolver.get(DuccPropertiesResolver.ducc_ws_port_ssl));
+				        String portHttp = ""+ConfigValue.PortHttp.getInt(DuccPropertiesResolver.get(DuccPropertiesResolver.ducc_ws_port));
+				        String s1Before = "http"+":";
+				        String s1After = "https"+":";
+				        String s2Before = ":"+portHttp;
+				        String s2After = ":"+portHttps;
+				        if(url.contains(s1Before)) {
+				        	if(url.contains(s2Before)) {
+				        		String redirect = new String(url);
+				        		redirect = redirect.replace(s1Before, s1After);
+				        		redirect = redirect.replace(s2Before, s2After);
+				        		if(!url.equals(redirect)) {
+				        			String content = getContentRedirect(redirect);
+									response.getWriter().println(content);
+									duccLogger.info(location, jobid, redirect);
+									response.setContentType("text/html;charset=utf-8");
+									response.setStatus(HttpServletResponse.SC_OK);
+									baseRequest.setHandled(true);
+									DuccWebUtil.noCache(response);
+				        		}
+				        	}
+				        }
+					}
+				}
+				break;
+			case unrestricted:
+			case blocked:
+			default:
+				break;
+			}
+		}
+	}
+	
+	@Override
+	public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
+		String location = "handle";
+		try{ 
+			duccLogger.debug(location, jobid,request.toString());
+			refresh();
+			handleRedirect(target, baseRequest, request, response);
+			handleForbidden(target, baseRequest, request, response);
+		}
+		catch(Throwable t) {
+			if(isIgnorable(t)) {
+				duccLogger.debug(location, jobid, t);
+			}
+			else {
+				duccLogger.info(location, jobid, "", t.getMessage(), t);
+				duccLogger.error(location, jobid, t);
+			}
+		}
+	}
+	
+}

Propchange: uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandlerHttpRequestFilter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccHandlerHttpRequestFilter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccWebServer.java
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccWebServer.java?rev=1773423&r1=1773422&r2=1773423&view=diff
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccWebServer.java (original)
+++ uima/uima-ducc/trunk/uima-ducc-web/src/main/java/org/apache/uima/ducc/ws/server/DuccWebServer.java Fri Dec  9 16:12:53 2016
@@ -308,6 +308,10 @@ public class DuccWebServer {
         SessionHandler sessionHandler = new SessionHandler();
         handlers.addHandler(sessionHandler);
         handlers.addHandler(duccHandlerUserAuthentication);
+        
+        DuccHandlerHttpRequestFilter httpRequestFilter = new DuccHandlerHttpRequestFilter(this);
+        handlers.addHandler(httpRequestFilter);
+        
         for(Handler handler: localHandlers) {
         	handlers.addHandler(handler);
         }

Added: uima/uima-ducc/trunk/uima-ducc-web/src/main/webapp/etc/http-uri-encryption-exemption.list
URL: http://svn.apache.org/viewvc/uima/uima-ducc/trunk/uima-ducc-web/src/main/webapp/etc/http-uri-encryption-exemption.list?rev=1773423&view=auto
==============================================================================
--- uima/uima-ducc/trunk/uima-ducc-web/src/main/webapp/etc/http-uri-encryption-exemption.list (added)
+++ uima/uima-ducc/trunk/uima-ducc-web/src/main/webapp/etc/http-uri-encryption-exemption.list Fri Dec  9 16:12:53 2016
@@ -0,0 +1,39 @@
+# list of URI prefixes that are exempt from encryption
+/opensources
+/ducc.css
+/js/ducc.js
+/js/ducc.local.js
+/ducc-servlet/cluster-name
+/ducc-servlet/version
+/ducc-servlet/home
+/ducc-servlet/alerts
+/ducc-servlet/banner-message
+/ducc-servlet/authenticator-version
+/ducc-servlet/timestamp
+/ducc-servlet/cluster-utilization
+/ducc-servlet/login-link
+/ducc-servlet/logout-link
+/ducc-servlet/authenticator-password-checked
+/favicon.ico
+/uima.ico
+/login.html
+/login.jsp
+/logout.html
+/logout.jsp
+/system.classes.jsp
+/system.classes.html
+/ducc-servlet/classic-system-classes-data
+/system.daemons.jsp
+/system.daemons.html
+/ducc-servlet/classic-system-daemons-data
+/system.machines.jsp
+/system.machines.html
+/ducc-servlet/classic-system-machines-data
+/ducc-servlet/proxy-job-status
+/ducc-servlet/proxy-job-monitor-report
+/ducc-servlet/proxy-reservation-status
+/ducc-servlet/proxy-reservation-monitor-report
+/ducc-servlet/proxy-managed-reservation-status
+/ducc-servlet/proxy-managed-reservation-monitor-report
+/preferences.jsp
+/doc/duccbook.html