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