|
34 | 34 | import javax.servlet.*; |
35 | 35 | import javax.servlet.http.HttpServletRequest; |
36 | 36 | import java.io.IOException; |
| 37 | +import java.util.ArrayList; |
| 38 | +import java.util.Arrays; |
| 39 | +import java.util.List; |
37 | 40 | import java.util.logging.Level; |
38 | 41 | import java.util.logging.Logger; |
39 | 42 | import java.util.regex.Pattern; |
@@ -79,14 +82,7 @@ static void setPattern(String pattern) throws PatternSyntaxException { |
79 | 82 | public void doFilter(ServletRequest request, ServletResponse res, FilterChain chain) |
80 | 83 | throws IOException, ServletException { |
81 | 84 | HttpServletRequest req = (HttpServletRequest) request; |
82 | | - String uri; |
83 | | - if (req.getPathInfo() == null) { |
84 | | - // workaround: on some containers such as CloudBees DEV@cloud, req.getPathInfo() is unexpectedly null, |
85 | | - // construct pathInfo based on contextPath and requestUri |
86 | | - uri = req.getRequestURI().substring(req.getContextPath().length()); |
87 | | - } else { |
88 | | - uri = req.getPathInfo(); |
89 | | - } |
| 85 | + String uri = getPathInfo(req); |
90 | 86 | if (uriPattern != null && uriPattern.matcher(uri).matches()) { |
91 | 87 | User user = User.current(); |
92 | 88 | String username = user != null ? user.getId() : req.getRemoteAddr(); |
@@ -151,4 +147,45 @@ private void onRequest(String uri, String extra, String username) { |
151 | 147 | } |
152 | 148 | } |
153 | 149 | } |
| 150 | + |
| 151 | + // See SECURITY-1815 |
| 152 | + private static String getPathInfo(HttpServletRequest request) { |
| 153 | + return canonicalPath(request.getRequestURI().substring(request.getContextPath().length())); |
| 154 | + } |
| 155 | + |
| 156 | + // Copied from Stapler#canonicalPath |
| 157 | + private static String canonicalPath(String path) { |
| 158 | + List<String> r = new ArrayList<>(Arrays.asList(path.split("/+"))); |
| 159 | + for (int i = 0; i < r.size(); ) { |
| 160 | + if (r.get(i).length() == 0 || r.get(i).equals(".")) { |
| 161 | + // empty token occurs for example, "".split("/+") is [""] |
| 162 | + r.remove(i); |
| 163 | + } else if (r.get(i).equals("..")) { |
| 164 | + // i==0 means this is a broken URI. |
| 165 | + r.remove(i); |
| 166 | + if (i > 0) { |
| 167 | + r.remove(i - 1); |
| 168 | + i--; |
| 169 | + } |
| 170 | + } else { |
| 171 | + i++; |
| 172 | + } |
| 173 | + } |
| 174 | + |
| 175 | + StringBuilder buf = new StringBuilder(); |
| 176 | + if (path.startsWith("/")) { |
| 177 | + buf.append('/'); |
| 178 | + } |
| 179 | + boolean first = true; |
| 180 | + for (String token : r) { |
| 181 | + if (!first) buf.append('/'); |
| 182 | + else first = false; |
| 183 | + buf.append(token); |
| 184 | + } |
| 185 | + // translation: if (path.endsWith("/") && !buf.endsWith("/")) |
| 186 | + if (path.endsWith("/") && (buf.length() == 0 || buf.charAt(buf.length() - 1) != '/')) { |
| 187 | + buf.append('/'); |
| 188 | + } |
| 189 | + return buf.toString(); |
| 190 | + } |
154 | 191 | } |
0 commit comments