Harden code 07/27307/2
authorst782s <statta@research.att.com>
Wed, 3 Jan 2018 19:30:16 +0000 (14:30 -0500)
committerTATTAVARADA <statta@research.att.com>
Wed, 3 Jan 2018 19:31:40 +0000 (14:31 -0500)
Issue-ID: PORTAL-145,PORTAL-119,PORTAL-118

Harden code to address SQL injecton, XSS vulnerabilities; Separate
docker images for portal, sdk app and DMaaPBC ui; Missing error page

Change-Id: I1818fbf86c601dd41b274729038e731fb2ec8f7d
Signed-off-by: st782s <statta@research.att.com>
26 files changed:
ecomp-sdk/epsdk-analytics/src/main/java/org/onap/portalsdk/analytics/model/SearchHandler.java
ecomp-sdk/epsdk-app-common/README.md
ecomp-sdk/epsdk-app-common/src/main/java/org/onap/portalapp/controller/core/FnMenuController.java
ecomp-sdk/epsdk-app-common/src/main/java/org/onap/portalapp/controller/core/ProfileController.java
ecomp-sdk/epsdk-app-common/src/main/java/org/onap/portalapp/controller/core/RoleController.java
ecomp-sdk/epsdk-app-common/src/main/java/org/onap/portalapp/controller/core/RoleListController.java
ecomp-sdk/epsdk-app-common/src/main/java/org/onap/portalapp/controller/core/SingleSignOnController.java
ecomp-sdk/epsdk-app-common/src/main/java/org/onap/portalapp/controller/sample/BroadcastController.java
ecomp-sdk/epsdk-app-common/src/main/java/org/onap/portalapp/controller/sample/BroadcastListController.java
ecomp-sdk/epsdk-app-common/src/main/java/org/onap/portalapp/util/SecurityXssValidator.java
ecomp-sdk/epsdk-app-os/README.md
ecomp-sdk/epsdk-app-os/db-scripts/EcompSdkDMLMySql_2_1_OS.sql
ecomp-sdk/epsdk-app-os/src/main/java/org/onap/portalapp/filter/SecurityXssFilter.java
ecomp-sdk/epsdk-app-os/src/main/webapp/WEB-INF/conf/system.properties
ecomp-sdk/epsdk-app-os/src/main/webapp/WEB-INF/web.xml
ecomp-sdk/epsdk-app-overlay/src/main/resources/ESAPI.properties
ecomp-sdk/epsdk-app-overlay/src/main/webapp/WEB-INF/jsp/error.jsp
ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/DS2-view-models/ds2-admin/modals/role-function-add.html
ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/scripts/DS2-view-models/ds2-admin/role_list.html
ecomp-sdk/epsdk-app-overlay/src/main/webapp/app/fusion/styles/ecomp.css
ecomp-sdk/epsdk-core/README.md
ecomp-sdk/epsdk-core/src/main/java/org/onap/portalsdk/core/interceptor/SessionTimeoutInterceptor.java
ecomp-sdk/epsdk-core/src/main/java/org/onap/portalsdk/core/logging/format/AlarmSeverityEnum.java
ecomp-sdk/epsdk-core/src/main/java/org/onap/portalsdk/core/service/UrlAccessImpl.java
ecomp-sdk/epsdk-core/src/main/java/org/onap/portalsdk/core/util/SystemProperties.java
ecomp-sdk/epsdk-workflow/src/main/java/org/onap/portalsdk/workflow/controllers/WorkflowController.java

index a6043ea..863f510 100644 (file)
@@ -295,7 +295,7 @@ public class SearchHandler extends org.onap.portalsdk.analytics.RaptorObject {
                } else {
                        rep_name_sql = " AND UPPER(cr.title) LIKE UPPER('%%') ";
                }
-               sql = sql.replace("[fReportName]", ESAPI.encoder().encodeForSQL( SecurityCodecUtil.getCodec(),rep_name_sql));
+               sql = sql.replace("[fReportName]",rep_name_sql);
 
                if (menuId.length() > 0){
                        /*sql += "AND INSTR('|'||cr.menu_id||'|', '|'||'" + menuId + "'||'|') > 0 "
index fa3e7bc..e72d942 100644 (file)
@@ -29,9 +29,9 @@ Version 1.4.0
 - PORTAL-42 Use OParent as parent POM
 - PORTAL-72 Address Sonar Scan code issues
 - PORTAL-90 Use approved ONAP license text
-- Portal-86 Remove application specific usages from tests and other files
+- PORTAL-86 Remove application specific usages from tests and other files
 - PORTAL-78 Fix SingleSignon by force session creation prior to redirection to portal
-
+- PORTAL-118 Missing Error page in Portal-SDK app when there is an exception happen in the backend.
 
 Version 1.3.0, 28 August 2017
 - Portal-19 Renaming the Group Id in the POM file to org.onap.portal.sdk
index dfc735b..c441417 100644 (file)
@@ -76,7 +76,7 @@ public class FnMenuController extends RestrictedBaseController {
 
        @Autowired
        FnMenuService service;
-       
+
        @Autowired
        FunctionalMenuListService functionalMenuListService;
 
@@ -91,7 +91,7 @@ public class FnMenuController extends RestrictedBaseController {
                        logger.error(EELFLoggerDelegate.errorLogger, "getParentListFailed", e);
                        response.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred in the getParentList () ");
                }
        }
 
@@ -104,7 +104,7 @@ public class FnMenuController extends RestrictedBaseController {
                        logger.error(EELFLoggerDelegate.errorLogger, "getFunctionCDList", e);
                        response.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred in the getFunctionCDList ()");
                }
 
        }
@@ -160,7 +160,6 @@ public class FnMenuController extends RestrictedBaseController {
                        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
                        JsonNode root = mapper.readTree(request.getReader());
                        Menu fnMenuItem = mapper.readValue(root.get("availableFnMenuItem").toString(), Menu.class);
-
                        service.saveFnMenu(fnMenuItem);
                        request.getSession()
                                        .removeAttribute(SystemProperties.getProperty(SystemProperties.APPLICATION_MENU_ATTRIBUTE_NAME));
@@ -183,7 +182,7 @@ public class FnMenuController extends RestrictedBaseController {
                        response.setCharacterEncoding("UTF-8");
                        request.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred in the updateFnMenu () ");
                }
                return null;
 
@@ -198,9 +197,7 @@ public class FnMenuController extends RestrictedBaseController {
                        JsonNode root = mapper.readTree(request.getReader());
                        Menu fnMenuItem = mapper.readValue(root.get("fnMenuItem").toString(), Menu.class);
                        Menu fnMenuItemRow = service.getMenuItemRow(fnMenuItem.getId());
-
                        service.removeMenuItem(fnMenuItemRow);
-
                        response.setCharacterEncoding("UTF-8");
                        response.setContentType("application / json");
                        request.setCharacterEncoding("UTF-8");
@@ -215,7 +212,7 @@ public class FnMenuController extends RestrictedBaseController {
                        response.setCharacterEncoding("UTF-8");
                        request.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred in the removeFnMenu ()");
                }
                return null;
 
index c83e926..b63d24a 100644 (file)
@@ -229,7 +229,7 @@ public class ProfileController extends RestrictedBaseController {
                        response.setCharacterEncoding("UTF-8");                 
                        try {
                                PrintWriter     out = response.getWriter();
-                               out.write(e.getMessage());
+                               out.write("An error occurred in the saveProfile ()");
                        } catch (IOException e1) {
                                logger.error(EELFLoggerDelegate.errorLogger, "saveProfile: failed to write", e1);
                        }
@@ -279,7 +279,7 @@ public class ProfileController extends RestrictedBaseController {
                        logger.error(EELFLoggerDelegate.errorLogger, "removeRole failed", e);
                        response.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred in the removeRole ()");
                        return null;
                }
        }
@@ -322,7 +322,7 @@ public class ProfileController extends RestrictedBaseController {
                        response.setCharacterEncoding("UTF-8");
                        request.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred in the addNewRole ()");
                        return null;
                }
 
index 69a25e6..bd1a6ab 100644 (file)
@@ -232,7 +232,7 @@ public class RoleController extends RestrictedBaseController {
                        logger.error(EELFLoggerDelegate.errorLogger, "removeRole failed", e);
                        response.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred removeRole failed in the removeRoleFunction");
                        return null;
                }
 
@@ -269,7 +269,7 @@ public class RoleController extends RestrictedBaseController {
                        logger.error(EELFLoggerDelegate.errorLogger, "removeRoleFunction failed", e);
                        response.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred removeRoleFunction failed in the removeRoleFunction");
                        return null;
                }
 
@@ -305,7 +305,7 @@ public class RoleController extends RestrictedBaseController {
                        logger.error(EELFLoggerDelegate.errorLogger, "removeChildRole failed", e);
                        response.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred removeChildRole failed in the removeChildRole()");
                        return null;
                }
 
@@ -342,7 +342,7 @@ public class RoleController extends RestrictedBaseController {
                        logger.error(EELFLoggerDelegate.errorLogger, "addChildRole failed", e);
                        response.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred addChildRole failed in the addChildRole()");
                        return null;
                }
 
index b89cb43..c7804e5 100644 (file)
@@ -141,7 +141,7 @@ public class RoleListController extends RestrictedBaseController {
                        logger.error(EELFLoggerDelegate.errorLogger, "toggleRole failed", e);
                        response.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred while saving Role  in the toggleRole()");
                        return null;
                }
 
@@ -180,7 +180,7 @@ public class RoleListController extends RestrictedBaseController {
                        response.setCharacterEncoding("UTF-8");
                        request.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred while removing Role  in the toggleRole()");
                        return null;
                }
 
index fb2e3b8..982a60b 100644 (file)
@@ -37,6 +37,8 @@
  */
 package org.onap.portalapp.controller.core;
 
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.net.URLDecoder;
 import java.net.URLEncoder;
 import java.util.HashMap;
@@ -47,6 +49,7 @@ import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 
+import org.apache.commons.lang.StringUtils;
 import org.onap.portalsdk.core.auth.LoginStrategy;
 import org.onap.portalsdk.core.command.LoginBean;
 import org.onap.portalsdk.core.controller.UnRestrictedBaseController;
@@ -159,6 +162,7 @@ public class SingleSignOnController extends UnRestrictedBaseController {
                                // both user and session are non-null.
                                logger.info(EELFLoggerDelegate.debugLogger, "singleSignOnLogin: redirecting to the forwardURL {}",
                                                forwardURL);
+                               validateDomain(forwardURL);
                                return new ModelAndView("redirect:" + forwardURL);
                        }
 
@@ -180,6 +184,7 @@ public class SingleSignOnController extends UnRestrictedBaseController {
                                // application can publish a base URL in system.properties
                                String appUrl = SystemProperties.getProperty(SystemProperties.APP_BASE_URL);
                                returnToAppUrl = appUrl + (appUrl.endsWith("/") ? "" : "/") + forwardURL;
+                               validateDomain(returnToAppUrl);
                                logger.debug(EELFLoggerDelegate.debugLogger,
                                                "singleSignOnLogin: using app base URL {} and redirectURL {}", appUrl, returnToAppUrl);
                        } else {
@@ -190,6 +195,7 @@ public class SingleSignOnController extends UnRestrictedBaseController {
                                // should always find the specified token.
                                returnToAppUrl = request.getRequestURL().toString().replace("single_signon.htm",
                                                forwardURL);
+                               validateDomain(returnToAppUrl);
                                logger.debug(EELFLoggerDelegate.debugLogger, "singleSignOnLogin: computed redirectURL {}",
                                                returnToAppUrl);
                        }
@@ -202,7 +208,6 @@ public class SingleSignOnController extends UnRestrictedBaseController {
                        final String redirectUrl = portalUrl + "?uebAppKey=" + uebAppKey + "&redirectUrl=" + encodedReturnToAppUrl;
                        logger.debug(EELFLoggerDelegate.debugLogger, "singleSignOnLogin: portal-bound redirect URL is {}",
                                        redirectUrl);
-                       
                        // this line may not be necessary but jsessionid coockie is not getting created in all cases;
                        // so force the cookie creation
                        request.getSession(true);
@@ -211,6 +216,17 @@ public class SingleSignOnController extends UnRestrictedBaseController {
                }
        }
 
+       private void validateDomain(String forwardURL) throws MalformedURLException {
+               if (StringUtils.isNotBlank(forwardURL)) {
+                       String hostName = new URL(forwardURL).getHost();
+                       if (StringUtils.isNotBlank(hostName) && !hostName.endsWith(SystemProperties.getProperty(SystemProperties.COOKIE_DOMAIN))) {
+                               logger.debug(EELFLoggerDelegate.debugLogger, "singleSignOnLogin: accessing Unauthorized url",
+                                               hostName);
+                               throw new SecurityException("accessing Unauthorized url : " + hostName);
+                       }
+               }
+       }
+
        protected void initateSessionMgtHandler(HttpServletRequest request) {
                String portalJSessionId = getPortalJSessionId(request);
                String jSessionId = getJessionId(request);
index 316f35c..c4f0d43 100644 (file)
@@ -45,8 +45,10 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.json.JSONObject;
+import org.onap.portalapp.util.SecurityXssValidator;
 import org.onap.portalsdk.core.controller.RestrictedBaseController;
 import org.onap.portalsdk.core.domain.BroadcastMessage;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
 import org.onap.portalsdk.core.service.BroadcastService;
 import org.onap.portalsdk.core.util.SystemProperties;
 import org.onap.portalsdk.core.web.support.AppUtils;
@@ -65,6 +67,8 @@ import com.fasterxml.jackson.databind.ObjectMapper;
 @RequestMapping("/")
 public class BroadcastController extends RestrictedBaseController {
 
+       private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(BroadcastController.class);
+       
        @Autowired
        private BroadcastService broadcastService;
 
@@ -77,7 +81,7 @@ public class BroadcastController extends RestrictedBaseController {
                        model.put("broadcastMessage", mapper.writeValueAsString(broadcastService.getBroadcastMessage(request)));
                        model.put("broadcastSites", mapper.writeValueAsString(referenceData(request).get("broadcastSites")));
                } catch (Exception e) {
-                       e.printStackTrace();
+                       logger.error(EELFLoggerDelegate.errorLogger, "broadcast() failed", e);
                }
                return new ModelAndView(getViewName(), model);
        }
@@ -96,7 +100,7 @@ public class BroadcastController extends RestrictedBaseController {
                        response.getWriter().write(j.toString());
 
                } catch (Exception e) {
-                       e.printStackTrace();
+                       logger.error(EELFLoggerDelegate.errorLogger, "getBroadcast() failed", e);
                }
 
        }
@@ -141,7 +145,8 @@ public class BroadcastController extends RestrictedBaseController {
                        response.setCharacterEncoding("UTF-8");
                        request.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred while saving the BroadcastMessage in the save () mapping-/broadcast/save   ");
+                       logger.error(EELFLoggerDelegate.errorLogger, "save() failed", e);
                        return null;
                }
 
index aeeaca5..2a9af81 100644 (file)
@@ -121,7 +121,7 @@ public class BroadcastListController extends RestrictedBaseController {
                        response.setCharacterEncoding("UTF-8");
                        request.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred while removing the BroadcastMessage in the remove ()");
                        logger.error(EELFLoggerDelegate.errorLogger, "remove() failed", e);
                        return null;
                }
@@ -156,7 +156,7 @@ public class BroadcastListController extends RestrictedBaseController {
                        response.setCharacterEncoding("UTF-8");
                        request.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred while saving the BroadcastMessage in the toggleActive () ");
                        logger.error(EELFLoggerDelegate.errorLogger, "toggleActive() failed", e);
                        return null;
                }
index b51cb8d..9754550 100644 (file)
@@ -60,6 +60,7 @@ public class SecurityXssValidator {
        private static final String MYSQL_DB = "mysql";
        private static final String ORACLE_DB = "oracle";
        private static final String MARIA_DB = "mariadb";
+       private static final int FLAGS = Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL;
 
        static SecurityXssValidator validator = null;
        private static Codec instance;
@@ -82,46 +83,39 @@ public class SecurityXssValidator {
 
        private SecurityXssValidator() {
                // Avoid anything between script tags
-               XSS_INPUT_PATTERNS.add(Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE));
+               XSS_INPUT_PATTERNS.add(Pattern.compile("<script>(.*?)</script>", FLAGS));
 
                // avoid iframes
-               XSS_INPUT_PATTERNS.add(Pattern.compile("<iframe(.*?)>(.*?)</iframe>", Pattern.CASE_INSENSITIVE));
+               XSS_INPUT_PATTERNS.add(Pattern.compile("<iframe(.*?)>(.*?)</iframe>", FLAGS));
 
                // Avoid anything in a src='...' type of expression
-               XSS_INPUT_PATTERNS.add(Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'",
-                               Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
+               XSS_INPUT_PATTERNS.add(Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", FLAGS));
 
-               XSS_INPUT_PATTERNS.add(Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"",
-                               Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
+               XSS_INPUT_PATTERNS.add(Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", FLAGS));
 
-               XSS_INPUT_PATTERNS.add(Pattern.compile("src[\r\n]*=[\r\n]*([^>]+)",
-                               Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
+               XSS_INPUT_PATTERNS.add(Pattern.compile("src[\r\n]*=[\r\n]*([^>]+)", FLAGS));
 
                // Remove any lonesome </script> tag
-               XSS_INPUT_PATTERNS.add(Pattern.compile("</script>", Pattern.CASE_INSENSITIVE));
+               XSS_INPUT_PATTERNS.add(Pattern.compile("</script>", FLAGS));
 
-               XSS_INPUT_PATTERNS.add(Pattern.compile(".*(<script>|</script>).*", Pattern.CASE_INSENSITIVE));
+               XSS_INPUT_PATTERNS.add(Pattern.compile(".*(<script>|</script>).*", FLAGS));
 
-               XSS_INPUT_PATTERNS.add(Pattern.compile(".*(<iframe>|</iframe>).*", Pattern.CASE_INSENSITIVE));
+               XSS_INPUT_PATTERNS.add(Pattern.compile(".*(<iframe>|</iframe>).*", FLAGS));
 
                // Remove any lonesome <script ...> tag
-               XSS_INPUT_PATTERNS
-                               .add(Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
+               XSS_INPUT_PATTERNS.add(Pattern.compile("<script(.*?)>", FLAGS));
 
                // Avoid eval(...) expressions
-               XSS_INPUT_PATTERNS
-                               .add(Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
+               XSS_INPUT_PATTERNS.add(Pattern.compile("eval\\((.*?)\\)", FLAGS));
 
                // Avoid expression(...) expressions
-               XSS_INPUT_PATTERNS.add(Pattern.compile("expression\\((.*?)\\)",
-                               Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
+               XSS_INPUT_PATTERNS.add(Pattern.compile("expression\\((.*?)\\)", FLAGS));
 
                // Avoid javascript:... expressions
-               XSS_INPUT_PATTERNS.add(Pattern.compile(".*(javascript:|vbscript:).*", Pattern.CASE_INSENSITIVE));
+               XSS_INPUT_PATTERNS.add(Pattern.compile(".*(javascript:|vbscript:).*", FLAGS));
 
                // Avoid onload= expressions
-               XSS_INPUT_PATTERNS.add(
-                               Pattern.compile(".*(onload(.*?)=).*", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL));
+               XSS_INPUT_PATTERNS.add(Pattern.compile(".*(onload(.*?)=).*", FLAGS));
        }
 
        private List<Pattern> XSS_INPUT_PATTERNS = new ArrayList<Pattern>();
index d9d7fb6..daf0323 100644 (file)
@@ -19,9 +19,11 @@ Version 1.4.0, <?day> <?month> 2017
 - PORTAL-72 Address Sonar Scan code issues
 - PORTAL-79 remove unwanted SDK left menu under Report-sample dashboard
 - PORTAL-90 Use approved ONAP license text
-- Portal-86 Remove application specific usages from tests and other files (rework)
-- Portal-104 Replaced the sql connector to maria db
-- Portal-127 Remove GreenSock license code from b2b library
+- PORTAL-86 Remove application specific usages from tests and other files (rework)
+- PORTAL-104 Replaced the sql connector to maria db
+- PORTAL-127 Remove GreenSock license code from b2b library
+- PORTAL-118 Missing Error page in Portal-SDK app when there is an exception happen in the backend.
+
 * Put new entries here *
 
 Version 1.3.0, 28 August 2017
index cb4a308..91402fb 100644 (file)
@@ -36,4 +36,16 @@ Insert into fn_app (APP_ID,APP_NAME,APP_IMAGE_URL,APP_DESCRIPTION,APP_NOTES,APP_
 -- fn_user_role
 Insert into fn_user_role (USER_ID,ROLE_ID,PRIORITY,APP_ID) values (1,1,null,1);
 
+-- fn_restricted_url
+insert into fn_restricted_url values('admin','menu_admin');
+insert into fn_restricted_url values('get_role','menu_admin');
+insert into fn_restricted_url values('get_role_functions','menu_admin');
+insert into fn_restricted_url values('role_list/*','menu_admin');
+insert into fn_restricted_url values('role_function_list/*','menu_admin');
+insert into fn_restricted_url values('addRole','menu_admin');
+insert into fn_restricted_url values('addRoleFunction','menu_admin');
+insert into fn_restricted_url values('removeRole','menu_admin');
+insert into fn_restricted_url values('removeRoleFunction','menu_admin');
+insert into fn_restricted_url values('profile/*','menu_admin');
+
 commit;
index 71ab735..aad0128 100644 (file)
  */
 package org.onap.portalapp.filter;
 
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.io.UnsupportedEncodingException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
 
 import javax.servlet.FilterChain;
+import javax.servlet.ReadListener;
 import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
+import org.apache.http.HttpStatus;
 import org.onap.portalapp.util.SecurityXssValidator;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
 import org.springframework.web.filter.OncePerRequestFilter;
-import org.springframework.web.util.ContentCachingRequestWrapper;
-import org.springframework.web.util.ContentCachingResponseWrapper;
-import org.springframework.web.util.WebUtils;
 
 public class SecurityXssFilter extends OncePerRequestFilter {
 
-       private static final String BAD_REQUEST = "BAD_REQUEST";
+       private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(SecurityXssFilter.class);
+
+       private static final String APPLICATION_JSON = "application/json";
+
+       private static final String ERROR_BAD_REQUEST = "{\"error\":\"BAD_REQUEST\"}";
 
        private SecurityXssValidator validator = SecurityXssValidator.getInstance();
 
-       private static String getRequestData(final HttpServletRequest request) throws UnsupportedEncodingException {
-               String payload = null;
-               ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
-               if (wrapper != null) {
-                       byte[] buf = wrapper.getContentAsByteArray();
-                       if (buf.length > 0) {
-                               payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
-                       }
+       public class RequestWrapper extends HttpServletRequestWrapper {
+
+               private ByteArrayOutputStream cachedBytes;
+
+               public RequestWrapper(HttpServletRequest request) {
+                       super(request);
                }
-               return payload;
-       }
 
-       private static String getResponseData(final HttpServletResponse response) throws IOException {
-               String payload = null;
-               ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response,
-                               ContentCachingResponseWrapper.class);
-               if (wrapper != null) {
-                       byte[] buf = wrapper.getContentAsByteArray();
-                       if (buf.length > 0) {
-                               payload = new String(buf, 0, buf.length, wrapper.getCharacterEncoding());
-                               wrapper.copyBodyToResponse();
+               @Override
+               public ServletInputStream getInputStream() throws IOException {
+                       if (cachedBytes == null)
+                               cacheInputStream();
+
+                       return new CachedServletInputStream();
+               }
+
+               @Override
+               public BufferedReader getReader() throws IOException {
+                       return new BufferedReader(new InputStreamReader(getInputStream()));
+               }
+
+               private void cacheInputStream() throws IOException {
+                       cachedBytes = new ByteArrayOutputStream();
+                       IOUtils.copy(super.getInputStream(), cachedBytes);
+               }
+
+               public class CachedServletInputStream extends ServletInputStream {
+                       private ByteArrayInputStream input;
+
+                       public CachedServletInputStream() {
+                               input = new ByteArrayInputStream(cachedBytes.toByteArray());
                        }
+
+                       @Override
+                       public int read() throws IOException {
+                               return input.read();
+                       }
+
+                       public boolean isFinished() {
+                               return false;
+                       }
+
+                       public boolean isReady() {
+                               return false;
+                       }
+
+                       public void setReadListener(ReadListener readListener) {
+
+                       }
+
                }
-               return payload;
        }
 
        @Override
        protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
                        throws ServletException, IOException {
-
-               if (request.getMethod().equalsIgnoreCase("POST") || request.getMethod().equalsIgnoreCase("PUT")) {
-
-                       HttpServletRequest requestToCache = new ContentCachingRequestWrapper(request);
-                       HttpServletResponse responseToCache = new ContentCachingResponseWrapper(response);
-                       filterChain.doFilter(requestToCache, responseToCache);
-                       String requestData = getRequestData(requestToCache);
-                       String responseData = getResponseData(responseToCache);
-                       if (StringUtils.isNotBlank(requestData) && validator.denyXSS(requestData)) {
-                               throw new SecurityException(BAD_REQUEST);
+               if (validateRequestType(request)) {
+                       request = new RequestWrapper(request);
+                       String requestData = IOUtils.toString(request.getInputStream(), StandardCharsets.UTF_8.toString());
+                       try {
+                               if (StringUtils.isNotBlank(requestData) && validator.denyXSS(requestData)) {
+                                       response.setContentType(APPLICATION_JSON);
+                                       response.setStatus(HttpStatus.SC_BAD_REQUEST);
+                                       response.getWriter().write(ERROR_BAD_REQUEST);
+                                       throw new SecurityException(ERROR_BAD_REQUEST);
+                               }
+                       } catch (Exception e) {
+                               logger.error(EELFLoggerDelegate.errorLogger, "doFilterInternal() failed due to BAD_REQUEST", e);
+                               response.getWriter().close();
+                               return;
                        }
+                       filterChain.doFilter(request, response);
 
                } else {
                        filterChain.doFilter(request, response);
                }
 
        }
-}
+
+       private boolean validateRequestType(HttpServletRequest request) {
+               return (request.getMethod().equalsIgnoreCase("POST") || request.getMethod().equalsIgnoreCase("PUT")
+                               || request.getMethod().equalsIgnoreCase("DELETE"));
+       }
+}
\ No newline at end of file
index de056a3..0dc8130 100644 (file)
@@ -69,4 +69,6 @@ instance_uuid=8da691c9-987d-43ed-a358-00ac2f35685d
 # app_base_url = https://www.openecomp.org/app_context/
 
 #authenticate user server
-authenticate_user_server=http://todo_enter_auth_server_hostname:8383/openid-connect-server-webapp/allUsers
\ No newline at end of file
+authenticate_user_server=http://todo_enter_auth_server_hostname:8383/openid-connect-server-webapp/allUsers
+#cookie domain 
+cookie_domain = onap.org
\ No newline at end of file
index f5039df..76a372b 100644 (file)
@@ -1,8 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee" 
-         xmlns:web="http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
-         version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee">
+       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee" xmlns:web="http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
+       version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee">
 
        <display-name>ecomp-sdk-app-os</display-name>
 
                <tracking-mode>COOKIE</tracking-mode>
        </session-config>
        <filter>
-    <filter-name>SecurityXssFilter</filter-name>
-    <filter-class>org.onap.portalapp.filter.SecurityXssFilter</filter-class>
-   </filter> 
-    <filter-mapping>
-    <filter-name>SecurityXssFilter</filter-name>
-    <url-pattern>/*</url-pattern>
-  </filter-mapping>
+               <filter-name>SecurityXssFilter</filter-name>
+               <filter-class>org.onap.portalapp.filter.SecurityXssFilter
+               </filter-class>
+       </filter>
+       <filter-mapping>
+               <filter-name>SecurityXssFilter</filter-name>
+               <url-pattern>/*</url-pattern>
+       </filter-mapping>
+       <error-page>
+               <location>/WEB-INF/jsp/error.jsp</location>
+       </error-page>
 
 </web-app>
\ No newline at end of file
index d06d602..3bf78f7 100644 (file)
@@ -6,7 +6,7 @@
 # If you need to troubleshoot a properties related problem, turning this on may help.
 # This is 'false' in the src/test/resources/.esapi version. It is 'true' by
 # default for reasons of backward compatibility with earlier ESAPI versions.
-ESAPI.printProperties=true
+ESAPI.printProperties=false
 
 # ESAPI is designed to be easily extensible. You can use the reference implementation
 # or implement your own providers to take advantage of your enterprise's security
index 3f31fe0..8e1c3a5 100644 (file)
@@ -6,7 +6,7 @@
   ===================================================================
  
   Unless otherwise specified, all software contained herein is licensed
-  under the Apache License, Version 2.0 (the “License”);
+  under the Apache License, Version 2.0 (the "License");
   you may not use this software except in compliance with the License.
   You may obtain a copy of the License at
  
@@ -19,7 +19,7 @@
   limitations under the License.
  
   Unless otherwise specified, all documentation contained herein is licensed
-  under the Creative Commons License, Attribution 4.0 Intl. (the â\80\9cLicenseâ\80\9d);
+  under the Creative Commons License, Attribution 4.0 Intl. (the \80License"Â\80Â\9d);
   you may not use this documentation except in compliance with the License.
   You may obtain a copy of the License at
  
  
   ECOMP is a trademark and service mark of AT&T Intellectual Property.
   --%>
-${errMsg}
+<%@ page language="java" contentType="text/html;"
+       pageEncoding="US-ASCII" isErrorPage="true"%>
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+       <head>
+               <meta http-equiv="Content-Type" content="text/html;">
+               <title>Error Page</title>
+       </head>
+       <body>
+               <h1>Something went wrong. Please go back to the previous page or
+                       try again later.</h1>
+                       
+               <h3>Please see the exception:</h3>
+       
+               <table width="100%" border="1">
+                       <tr valign="top">
+                               <td width="40%"><b>Error:</b></td>
+                               <td>${pageContext.exception}</td>
+                       </tr>
+       
+                       <tr valign="top">
+                               <td><b>URI:</b></td>
+                               <td>${pageContext.errorData.requestURI}</td>
+                       </tr>
+       
+                       <tr valign="top">
+                               <td><b>Status code:</b></td>
+                               <td>${pageContext.errorData.statusCode}</td>
+                       </tr>
+               </table>
+       
+       </body>
+</html>
\ No newline at end of file
index a691257..531c55e 100644 (file)
                style="height: 145px;">
 
                <div class="field-group">
-                       Name <input id="textinputID-2a" ddh-reset ng-model="roleFun['name']"
+                       <span ID="required" style="color: Red;" visible="false"> *</span>Name <input id="textinputID-2a" ddh-reset ng-model="roleFun['name']"
                                placeholder="Name" class="span12" type="text">
                </div>
+               <div class="error-container"
+                       ng-show="!roleFun['name']||roleFun['name']==0">
+                       <small id="name-required" class="err-message">Name is Required</small>
+               </div>
+               <br>
                <div class="field-group">
-                       Code <input id="textinputID-2a" ddh-reset ng-model="roleFun['code']"
+                       <span ID="required" style="color: Red;" visible="false"> *</span>Code <input id="textinputID-2a" ddh-reset ng-model="roleFun['code']"
                                placeholder="Code" class="span12" type="text">
 
                </div>
+               <div class="error-container"
+                       ng-show="!roleFun['code']||roleFun['code']==0">
+                       <small id="code-required" class="err-message">Code is Required</small>
+               </div>
+               
        </div>
+       <br>
        <div class="b2b-modal-footer ng-scope ng-isolate-scope in">
                <div class="cta-button-group in">
-                       <button class="btn btn-alt btn-medium" type="button"
+                       <button class="btn btn-alt btn-medium" type="button" ng-disabled= "(!roleFun['name']||roleFun['name']==0)|| (!roleFun['code']||roleFun['code']==0)"
                                ng-click="save(roleFun);">Create</button>
                        <button class="btn btn-medium" type="button"
                                ng-click="$dismiss('cancel')">Cancel</button>
index e325b8a..e8820f9 100644 (file)
@@ -9,7 +9,7 @@
        </div>
        <div ng-hide="showLoader">
                <div>
-                        <button type="submit" ng-click="addRoleFuncPopUp(rowData);" class="btn btn-alt btn-small" ng-if="isAppCentralized=='false'">Add New Role</button>
+                        <button type="submit"  onClick="window.location='admin#/role/0';" class="btn btn-alt btn-small" ng-if="isAppCentralized=='false'">Add New Role</button>
                </div>
                <h2 class="heading-small" ng-if="isAppCentralized=='false'">Click on a Role to view its details.</h2>
                        <table class="striped" ng-if="availableRoleFunctions" style="width: auto;">
index 4c780f3..635ede4 100644 (file)
@@ -180,4 +180,15 @@ p,a{
        max-height:300px; 
        overflow:auto; 
        display:block
+}
+.error-container {
+    position: absolute;
+    width: 220px;
+    display: block;
+    height: 12px;
+    line-height: 12px;
+}
+.err-message {
+    color: #cf2a2a;
+    font-size: 10px;
 }
\ No newline at end of file
index fbc2bf2..55cf69f 100644 (file)
@@ -14,7 +14,8 @@ ECOMP SDK web application.
 ### ONAP Distributions
 
 Version 2.1.0
-- PORTAL-19 Rename Java package base to org.onap
+- PORTAL-19  Rename Java package base to org.onap
+- PORTAL-145 Harden code to address penetration attacks
 
 Version 1.4.0
 - PORTAL-19 Rename Java package base to org.onap
index 809266d..a6b98fd 100644 (file)
  */
 package org.onap.portalsdk.core.interceptor;
 
+import java.net.MalformedURLException;
+import java.net.URL;
 import java.net.URLEncoder;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
+import org.apache.commons.lang.StringUtils;
 import org.onap.portalsdk.core.controller.FusionBaseController;
 import org.onap.portalsdk.core.domain.User;
 import org.onap.portalsdk.core.exception.SessionExpiredException;
 import org.onap.portalsdk.core.listener.CollaborateListBindingListener;
 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.portalsdk.core.util.SystemProperties;
 import org.onap.portalsdk.core.web.support.AppUtils;
 import org.onap.portalsdk.core.web.support.UserUtils;
 import org.springframework.web.method.HandlerMethod;
@@ -56,7 +60,7 @@ import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
 public class SessionTimeoutInterceptor extends HandlerInterceptorAdapter {
 
        private static final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(SessionTimeoutInterceptor.class);
-       
+
        /**
         * Checks all requests for valid session information. If not found, redirects to
         * a controller that will establish a valid session.
@@ -98,6 +102,7 @@ public class SessionTimeoutInterceptor extends HandlerInterceptorAdapter {
                                                // "/context/single_signon.htm"
                                                final String redirectUrl = request.getContextPath() + singleSignonPrefix
                                                                + "redirectToPortal=Yes&" + forwardUrlParm;
+                                               validateDomain(redirectUrl);
                                                logger.debug(EELFLoggerDelegate.debugLogger, "preHandle: session is expired, redirecting to {}",
                                                                redirectUrl);
                                                response.sendRedirect(redirectUrl);
@@ -107,6 +112,7 @@ public class SessionTimeoutInterceptor extends HandlerInterceptorAdapter {
                                                // Redirect to an absolute path in the webapp; e.g.,
                                                // "/context/single_signon.htm"
                                                final String redirectUrl = request.getContextPath() + singleSignonPrefix + forwardUrlParm;
+                                               validateDomain(redirectUrl);
                                                logger.debug(EELFLoggerDelegate.debugLogger, "preHandle: took exception {}, redirecting to {}",
                                                                ex.getMessage(), redirectUrl);
                                                response.sendRedirect(redirectUrl);
@@ -119,4 +125,15 @@ public class SessionTimeoutInterceptor extends HandlerInterceptorAdapter {
                return super.preHandle(request, response, handler);
        }
 
+       private void validateDomain(final String redirectUrl) throws MalformedURLException {
+               if (StringUtils.isNotBlank(redirectUrl)) {
+                       String hostName = new URL(redirectUrl).getHost();
+                       if (StringUtils.isNotBlank(hostName)
+                                       && !hostName.endsWith(SystemProperties.getProperty(SystemProperties.COOKIE_DOMAIN))) {
+                               logger.debug(EELFLoggerDelegate.debugLogger, "singleSignOnLogin: accessing Unauthorized url", hostName);
+                               throw new SecurityException("accessing Unauthorized url : " + hostName);
+                       }
+               }
+       }
+
 }
index 5e20247..c2ce2b3 100644 (file)
 package org.onap.portalsdk.core.logging.format;
 
 public enum AlarmSeverityEnum {
-       CRITICAL, MAJOR, MINOR, INFORMATIONAL, NONE,
+       CRITICAL("1"),
+       MAJOR("2"), 
+       MINOR("3"), 
+       INFORMATIONAL("4"), 
+       NONE("0");
+
+       private final String severity;
+
+       AlarmSeverityEnum(String severity) {
+               this.severity = severity;
+       }
+
+       public String severity() {
+               return severity;
+       }
 }
index 4dde611..ddadc10 100644 (file)
  */
 package org.onap.portalsdk.core.service;
 
-import java.util.HashMap;
+import java.util.ArrayList;
 import java.util.List;
-import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.servlet.http.HttpServletRequest;
 
+import org.hibernate.criterion.Criterion;
+import org.hibernate.criterion.Restrictions;
 import org.onap.portalsdk.core.domain.UrlsAccessible;
 import org.onap.portalsdk.core.web.support.UserUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -59,17 +62,18 @@ public class UrlAccessImpl implements UrlAccessService {
        @Override
        public boolean isUrlAccessible(HttpServletRequest request, String currentUrl) {
                boolean isAccessible = false;
-               Map<String, String> params = new HashMap<>();
-               params.put("current_url", currentUrl);
-               List list = dataAccessService.executeNamedQuery("restrictedUrls", params, null);
+               List<?> list = getAccessUrlList(currentUrl);
 
                // loop through the list of restricted URL's
                if (list != null && !list.isEmpty()) {
                        for (int i = 0; i < list.size(); i++) {
-                               UrlsAccessible urlFunctions = (UrlsAccessible) list.get(i);
-                               String functionCd = urlFunctions.getFunctionCd();
+                               UrlsAccessible urlFunction = (UrlsAccessible) list.get(i);
+                               if (!matchPattern(currentUrl, urlFunction.getUrl()))
+                                       continue;
+                               String functionCd = urlFunction.getFunctionCd();
                                if (UserUtils.isAccessible(request, functionCd)) {
                                        isAccessible = true;
+                                       break;
                                }
                        }
                        return isAccessible;
@@ -77,4 +81,68 @@ public class UrlAccessImpl implements UrlAccessService {
                return true;
        }
 
+       /*
+        * This Method returns all the entries in the database that start with the
+        * first part of the currentUrl split at the "/" character. 
+        * 
+        * Example: if currentUrl
+        * is "xyz/abc/1", all the entries in the corresponding tables that match
+        * with "xyz" are returned
+        */
+       private List<?> getAccessUrlList(String currentUrl) {
+               List<?> list = null;
+
+               if (currentUrl != null) {
+                       int indexOfSlash = currentUrl.indexOf("/");
+                       String currentFirstUrl = (indexOfSlash > 0) ? currentUrl.substring(0, indexOfSlash) : currentUrl;
+
+                       if (currentFirstUrl != null) {
+
+                               List<Criterion> restrictionsList = new ArrayList<Criterion>();
+                               Criterion criterion1 = Restrictions.like("urlsAccessibleKey.url", currentFirstUrl + "%");
+                               restrictionsList.add(criterion1);
+                               list = dataAccessService.getList(UrlsAccessible.class, null, restrictionsList, null);
+
+                       }
+               }
+               return list;
+       }
+
+       /*
+        * This method compares the portalApiPath against the urlPattern; splits the
+        * portalApiPath by "/" and compares each part with that of the urlPattern.
+        * 
+        * Example: "xyz/1/abc" matches with the pattern "xyz/* /abc" but not with
+        * "xyz/*"
+        * 
+        */
+
+       private Boolean matchPattern(String portalApiPath, String urlPattern) {
+               String[] path = portalApiPath.split("/");
+               if (path.length > 1) {
+
+                       String[] roleFunctionArray = urlPattern.split("/");
+                       boolean match = true;
+                       if (roleFunctionArray.length == path.length) {
+                               for (int i = 0; i < roleFunctionArray.length; i++) {
+                                       if (match) {
+                                               if (!roleFunctionArray[i].equals("*")) {
+                                                       Pattern p = Pattern.compile(path[i], Pattern.CASE_INSENSITIVE);
+                                                       Matcher m = p.matcher(roleFunctionArray[i]);
+                                                       match = m.matches();
+
+                                               }
+                                       }
+                               }
+                               if (match)
+                                       return match;
+                       }
+               } else {
+                       if (portalApiPath.matches(urlPattern))
+                               return true;
+
+               }
+               return false;
+       }
+
 }
index 6f11910..b6b03a4 100644 (file)
@@ -263,6 +263,8 @@ public class SystemProperties {
        // Left Menu
        public static final String LEFT_MENU_PARENT = "parentList";
        public static final String LEFT_MENU_CHILDREND = "childItemList";
+       public static final String COOKIE_DOMAIN = "cookie_domain";
+
 
        public enum RESULT_ENUM {
                SUCCESS, FAILURE
index 4238682..b4ceb6f 100644 (file)
@@ -103,7 +103,7 @@ public class WorkflowController extends RestrictedBaseController {
                        response.setCharacterEncoding("UTF-8");
                        request.setCharacterEncoding("UTF-8");
                        PrintWriter out = response.getWriter();
-                       out.write(e.getMessage());
+                       out.write("An error occurred while removing Role  in the toggleRole()");
                }
 
        }