Author: markt
Date: Wed Jun 19 21:43:26 2013
New Revision: 1494779

URL: http://svn.apache.org/r1494779
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=53987
Servlet 3.1. Log uncovered HTTP methods.

Modified:
    tomcat/trunk/java/org/apache/catalina/core/LocalStrings.properties
    tomcat/trunk/java/org/apache/catalina/core/StandardContext.java

Modified: tomcat/trunk/java/org/apache/catalina/core/LocalStrings.properties
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/LocalStrings.properties?rev=1494779&r1=1494778&r2=1494779&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/LocalStrings.properties 
(original)
+++ tomcat/trunk/java/org/apache/catalina/core/LocalStrings.properties Wed Jun 
19 21:43:26 2013
@@ -139,6 +139,8 @@ standardContext.servletMap.pattern=Inval
 standardContext.startFailed=Context [{0}] startup failed due to previous errors
 standardContext.startingContext=Exception starting Context with name [{0}]
 standardContext.stoppingContext=Exception stopping Context with name [{0}]
+standardContext.uncoveredHttpMethod=For security constraints with URL pattern 
[{0}] only the HTTP methods [{1}] are covered. All other methods are uncovered.
+standardContext.uncoveredHttpOmittedMethod=For security constraints with URL 
pattern [{0}] the HTTP methods [{1}] are uncovered.
 standardContext.urlPattern.patternWarning=WARNING: URL pattern {0} must start 
with a ''/'' in Servlet 2.4
 standardContext.webappClassLoader.missingProperty=Unable to set the web 
application class loader property [{0}] to [{1}] as the property does not exist.
 standardContext.workPath=Exception obtaining work path for context [{0}]

Modified: tomcat/trunk/java/org/apache/catalina/core/StandardContext.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardContext.java?rev=1494779&r1=1494778&r2=1494779&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/StandardContext.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/StandardContext.java Wed Jun 19 
21:43:26 2013
@@ -5271,6 +5271,13 @@ public class StandardContext extends Con
                 }
             }
 
+            // Check constraints for uncovered HTTP methods
+            // Needs to be after SCIs and listeners as they may programatically
+            // change constraints
+            if (ok) {
+                checkConstraintsForUncoveredMethods();
+            }
+
             try {
                 // Start manager
                 Manager manager = getManager();
@@ -5334,6 +5341,107 @@ public class StandardContext extends Con
         }
     }
 
+
+    private void checkConstraintsForUncoveredMethods() {
+        // TODO - Add an option to lower the log level of any uncovered method
+        //        warnings to debug
+        // TODO - Implement adding constraints to deny uncovered methods
+        Set<String> coveredPatterns = new HashSet<>();
+        Map<String,Set<String>> urlMethodMap = new HashMap<>();
+        Map<String,Set<String>> urlOmittedMethodMap = new HashMap<>();
+
+        // First build the lists of covered patterns and those patterns that
+        // might be uncovered
+        for (SecurityConstraint constraint : constraints) {
+            SecurityCollection[] collections = constraint.findCollections();
+            for (SecurityCollection collection : collections) {
+                String[] patterns = collection.findPatterns();
+                String[] methods = collection.findMethods();
+                String[] omittedMethods = collection.findOmittedMethods();
+                // Simple case: no methods
+                if (methods.length == 0 && omittedMethods.length == 0) {
+                    for (String pattern : patterns) {
+                        coveredPatterns.add(pattern);
+                    }
+                    continue;
+                }
+
+                // Pre-calculate so we don't do this for every iteration of the
+                // following loop
+                List<String> omNew = null;
+                if (omittedMethods.length == 0) {
+                    omNew = Arrays.asList(omittedMethods);
+                }
+
+                // Only need to process uncovered patterns
+                for (String pattern : patterns) {
+                    if (!coveredPatterns.contains(pattern)) {
+                        if (methods.length == 0) {
+                            // Build the interset of omitted methods for this
+                            // pattern
+                            Set<String> om = urlOmittedMethodMap.get(pattern);
+                            if (om == null) {
+                                om = new HashSet<>();
+                                urlMethodMap.put(pattern, om);
+                            }
+                            om.retainAll(omNew);
+                        } else {
+                            // Build the union of methods for this pattern
+                            Set<String> m = urlMethodMap.get(pattern);
+                            if (m == null) {
+                                m = new HashSet<>();
+                                urlMethodMap.put(pattern, m);
+                            }
+                            for (String method : methods) {
+                                m.add(method);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        // Now check the potentially uncovered patterns
+        for (Map.Entry<String, Set<String>> entry : urlMethodMap.entrySet()) {
+            String pattern = entry.getKey();
+            if (coveredPatterns.contains(pattern)) {
+                // Fully covered. Ignore any partial coverage
+                urlOmittedMethodMap.remove(pattern);
+                continue;
+            }
+
+            Set<String> omittedMethods = urlOmittedMethodMap.get(pattern);
+            Set<String> methods = entry.getValue();
+
+            if (omittedMethods == null) {
+                StringBuilder msg = new StringBuilder();
+                for (String method : methods) {
+                    msg.append(method);
+                    msg.append(' ');
+                }
+                log.error(sm.getString("standardContext.uncoveredHttpMethod",
+                        pattern, msg.toString().trim()));
+                continue;
+            }
+
+            // As long as every omitted method as a corresponding method the
+            // pattern is fully covered.
+            omittedMethods.removeAll(methods);
+
+            if (omittedMethods.size() > 0) {
+                StringBuilder msg = new StringBuilder();
+                for (String method : omittedMethods) {
+                    msg.append(method);
+                    msg.append(' ');
+                }
+                log.error(sm.getString(
+                        "standardContext.uncoveredHttpOmittedMethod",
+                        pattern, msg.toString().trim()));
+            }
+        }
+    }
+
+
     private void setClassLoaderProperty(String name, boolean value) {
         ClassLoader cl = getLoader().getClassLoader();
         if (!IntrospectionUtils.setProperty(cl, name, 
Boolean.toString(value))) {



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to