CVE-2014-8114 (published 2015-02-20T16:59Z)

The UberFire Framework 0.3.x does not properly restrict paths, which allows remote attackers to (1) execute arbitrary code by uploading crafted content to FileUploadServlet or (2) read arbitrary files via vectors involving FileDownloadServlet.

Severity: MEDIUM
CVSS v2 base score: 6.8 (AV:N/AC:M/Au:N/C:P/I:P/A:P)

Weakness information:
cwe_id: CWE-264
cwe_name: Permissions, Privileges, and Access Controls
description: Weaknesses in this category are related to the management of permissions, privileges, and other security features that are used to perform access control.

Fix information:
repo_url: https://github.com/uberfire/uberfire
commit_details: repo_url: https://github.com/uberfire/uberfire
author: Alexandre Porcelli
author_date: 2014-12-23 11:35:18-03:00
msg: BZ(1169544,1169556, 1169557,1169559,1169560): improvements on security related to file access
repository: repo_url: https://github.com/uberfire/uberfire
repo_name: AppFormer/uberfire
description: Uberfire Framework
owner: uberfire
file_changes: filename: AntPathMatcher.java
change_type: ModificationType.RENAME
diff: @@ -1,20 +1,4 @@
-/*
- * Copyright 2012 JBoss Inc
- *
- * Licensed 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.uberfire.security.server.util;
+package org.uberfire.commons.regex.util;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -39,20 +23,22 @@ public class AntPathMatcher {
      * Set the path separator to use for pattern parsing. Default is "/", as in
      * Ant.
      */
-    public void setPathSeparator(final String pathSeparator) {
+    public void setPathSeparator( final String pathSeparator ) {
         this.pathSeparator = pathSeparator != null ? pathSeparator : DEFAULT_PATH_SEPARATOR;
     }
 
-    public boolean isPattern(final String path) {
-        return path.indexOf('*') != -1 || path.indexOf('?') != -1;
+    public boolean isPattern( final String path ) {
+        return path.indexOf( '*' ) != -1 || path.indexOf( '?' ) != -1;
     }
 
-    public boolean match(final String pattern, final String path) {
-        return doMatch(pattern, path, true);
+    public boolean match( final String pattern,
+                          final String path ) {
+        return doMatch( pattern, path, true );
     }
 
-    public boolean matchStart(final String pattern, final String path) {
-        return doMatch(pattern, path, false);
+    public boolean matchStart( final String pattern,
+                               final String path ) {
+        return doMatch( pattern, path, false );
     }
 
     /**
@@ -63,15 +49,17 @@ public class AntPathMatcher {
      * @param fullMatch whether a full pattern match is required (else a pattern
      * match as far as the given base path goes is sufficient)
      * @return <code>true</code> if the supplied <code>path</code> matched,
-     *         <code>false</code> if it didn't
+     * <code>false</code> if it didn't
      */
-    protected boolean doMatch(String pattern, String path, boolean fullMatch) {
-        if (path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) {
+    protected boolean doMatch( String pattern,
+                               String path,
+                               boolean fullMatch ) {
+        if ( path.startsWith( this.pathSeparator ) != pattern.startsWith( this.pathSeparator ) ) {
             return false;
         }
 
-        String[] pattDirs = tokenizeToStringArray(pattern, this.pathSeparator);
-        String[] pathDirs = tokenizeToStringArray(path, this.pathSeparator);
+        String[] pattDirs = tokenizeToStringArray( pattern, this.pathSeparator );
+        String[] pathDirs = tokenizeToStringArray( path, this.pathSeparator );
 
         int pattIdxStart = 0;
         int pattIdxEnd = pattDirs.length - 1;
@@ -79,76 +67,76 @@ public class AntPathMatcher {
         int pathIdxEnd = pathDirs.length - 1;
 
         // Match all elements up to the first **
-        while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
-            String patDir = pattDirs[pattIdxStart];
-            if ("**".equals(patDir)) {
+        while ( pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd ) {
+            String patDir = pattDirs[ pattIdxStart ];
+            if ( "**".equals( patDir ) ) {
                 break;
             }
-            if (!matchStrings(patDir, pathDirs[pathIdxStart])) {
+            if ( !matchStrings( patDir, pathDirs[ pathIdxStart ] ) ) {
                 return false;
             }
             pattIdxStart++;
             pathIdxStart++;
         }
 
-        if (pathIdxStart > pathIdxEnd) {
+        if ( pathIdxStart > pathIdxEnd ) {
             // Path is exhausted, only match if rest of pattern is * or **'s
-            if (pattIdxStart > pattIdxEnd) {
-                return pattern.endsWith(this.pathSeparator) ? path.endsWith(this.pathSeparator) : !path
-                        .endsWith(this.pathSeparator);
+            if ( pattIdxStart > pattIdxEnd ) {
+                return pattern.endsWith( this.pathSeparator ) ? path.endsWith( this.pathSeparator ) : !path
+                        .endsWith( this.pathSeparator );
             }
-            if (!fullMatch) {
+            if ( !fullMatch ) {
                 return true;
             }
-            if (pattIdxStart == pattIdxEnd && pattDirs[pattIdxStart].equals("*")
-                    && path.endsWith(this.pathSeparator)) {
+            if ( pattIdxStart == pattIdxEnd && pattDirs[ pattIdxStart ].equals( "*" )
+                    && path.endsWith( this.pathSeparator ) ) {
                 return true;
             }
-            for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
-                if (!pattDirs[i].equals("**")) {
+            for ( int i = pattIdxStart; i <= pattIdxEnd; i++ ) {
+                if ( !pattDirs[ i ].equals( "**" ) ) {
                     return false;
                 }
             }
             return true;
-        } else if (pattIdxStart > pattIdxEnd) {
+        } else if ( pattIdxStart > pattIdxEnd ) {
             // String not exhausted, but pattern is. Failure.
             return false;
-        } else if (!fullMatch && "**".equals(pattDirs[pattIdxStart])) {
+        } else if ( !fullMatch && "**".equals( pattDirs[ pattIdxStart ] ) ) {
             // Path start definitely matches due to "**" part in pattern.
             return true;
         }
 
         // up to last '**'
-        while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) {
-            String patDir = pattDirs[pattIdxEnd];
-            if (patDir.equals("**")) {
+        while ( pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd ) {
+            String patDir = pattDirs[ pattIdxEnd ];
+            if ( patDir.equals( "**" ) ) {
                 break;
             }
-            if (!matchStrings(patDir, pathDirs[pathIdxEnd])) {
+            if ( !matchStrings( patDir, pathDirs[ pathIdxEnd ] ) ) {
                 return false;
             }
             pattIdxEnd--;
             pathIdxEnd--;
         }
-        if (pathIdxStart > pathIdxEnd) {
+        if ( pathIdxStart > pathIdxEnd ) {
             // String is exhausted
-            for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
-                if (!pattDirs[i].equals("**")) {
+            for ( int i = pattIdxStart; i <= pattIdxEnd; i++ ) {
+                if ( !pattDirs[ i ].equals( "**" ) ) {
                     return false;
                 }
             }
             return true;
         }
 
-        while (pattIdxStart != pattIdxEnd && pathIdxStart <= pathIdxEnd) {
+        while ( pattIdxStart != pattIdxEnd && pathIdxStart <= pathIdxEnd ) {
             int patIdxTmp = -1;
-            for (int i = pattIdxStart + 1; i <= pattIdxEnd; i++) {
-                if (pattDirs[i].equals("**")) {
+            for ( int i = pattIdxStart + 1; i <= pattIdxEnd; i++ ) {
+                if ( pattDirs[ i ].equals( "**" ) ) {
                     patIdxTmp = i;
                     break;
                 }
             }
-            if (patIdxTmp == pattIdxStart + 1) {
+            if ( patIdxTmp == pattIdxStart + 1 ) {
                 // '**/**' situation, so skip one
                 pattIdxStart++;
                 continue;
@@ -160,11 +148,11 @@ public class AntPathMatcher {
             int foundIdx = -1;
 
             strLoop:
-            for (int i = 0; i <= strLength - patLength; i++) {
-                for (int j = 0; j < patLength; j++) {
-                    String subPat = pattDirs[pattIdxStart + j + 1];
-                    String subStr = pathDirs[pathIdxStart + i + j];
-                    if (!matchStrings(subPat, subStr)) {
+            for ( int i = 0; i <= strLength - patLength; i++ ) {
+                for ( int j = 0; j < patLength; j++ ) {
+                    String subPat = pattDirs[ pattIdxStart + j + 1 ];
+                    String subStr = pathDirs[ pathIdxStart + i + j ];
+                    if ( !matchStrings( subPat, subStr ) ) {
                         continue strLoop;
                     }
                 }
@@ -172,7 +160,7 @@ public class AntPathMatcher {
                 break;
             }
 
-            if (foundIdx == -1) {
+            if ( foundIdx == -1 ) {
                 return false;
             }
 
@@ -180,8 +168,8 @@ public class AntPathMatcher {
             pathIdxStart = foundIdx + patLength;
         }
 
-        for (int i = pattIdxStart; i <= pattIdxEnd; i++) {
-            if (!pattDirs[i].equals("**")) {
+        for ( int i = pattIdxStart; i <= pattIdxEnd; i++ ) {
+            if ( !pattDirs[ i ].equals( "**" ) ) {
                 return false;
             }
         }
@@ -198,9 +186,10 @@ public class AntPathMatcher {
      * @param str string which must be matched against the pattern. Must not be
      * <code>null</code>.
      * @return <code>true</code> if the string matches against the pattern, or
-     *         <code>false</code> otherwise.
+     * <code>false</code> otherwise.
      */
-    private boolean matchStrings(String pattern, String str) {
+    private boolean matchStrings( String pattern,
+                                  String str ) {
         char[] patArr = pattern.toCharArray();
         char[] strArr = str.toCharArray();
         int patIdxStart = 0;
@@ -210,22 +199,22 @@ public class AntPathMatcher {
         char ch;
 
         boolean containsStar = false;
-        for (char c : patArr) {
-            if (c == '*') {
+        for ( char c : patArr ) {
+            if ( c == '*' ) {
                 containsStar = true;
                 break;
             }
         }
 
-        if (!containsStar) {
+        if ( !containsStar ) {
             // No '*'s, so we make a shortcut
-            if (patIdxEnd != strIdxEnd) {
+            if ( patIdxEnd != strIdxEnd ) {
                 return false; // Pattern and string do not have the same size
             }
-            for (int i = 0; i <= patIdxEnd; i++) {
-                ch = patArr[i];
-                if (ch != '?') {
-                    if (ch != strArr[i]) {
+            for ( int i = 0; i <= patIdxEnd; i++ ) {
+                ch = patArr[ i ];
+                if ( ch != '?' ) {
+                    if ( ch != strArr[ i ] ) {
                         return false;
                         // Character mismatch
                     }
@@ -234,14 +223,14 @@ public class AntPathMatcher {
             return true; // String matches against pattern
         }
 
-        if (patIdxEnd == 0) {
+        if ( patIdxEnd == 0 ) {
             return true; // Pattern contains only '*', which matches anything
         }
 
         // Process characters before first star
-        while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) {
-            if (ch != '?') {
-                if (ch != strArr[strIdxStart]) {
+        while ( ( ch = patArr[ patIdxStart ] ) != '*' && strIdxStart <= strIdxEnd ) {
+            if ( ch != '?' ) {
+                if ( ch != strArr[ strIdxStart ] ) {
                     return false;
                     // Character mismatch
                 }
@@ -249,11 +238,11 @@ public class AntPathMatcher {
             patIdxStart++;
             strIdxStart++;
         }
-        if (strIdxStart > strIdxEnd) {
+        if ( strIdxStart > strIdxEnd ) {
             // All characters in the string are used. Check if only '*'s are
             // left in the pattern. If so, we succeeded. Otherwise failure.
-            for (int i = patIdxStart; i <= patIdxEnd; i++) {
-                if (patArr[i] != '*') {
+            for ( int i = patIdxStart; i <= patIdxEnd; i++ ) {
+                if ( patArr[ i ] != '*' ) {
                     return false;
                 }
             }
@@ -261,9 +250,9 @@ public class AntPathMatcher {
         }
 
         // Process characters after last star
-        while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) {
-            if (ch != '?') {
-                if (ch != strArr[strIdxEnd]) {
+        while ( ( ch = patArr[ patIdxEnd ] ) != '*' && strIdxStart <= strIdxEnd ) {
+            if ( ch != '?' ) {
+                if ( ch != strArr[ strIdxEnd ] ) {
                     return false;
                     // Character mismatch
                 }
@@ -271,11 +260,11 @@ public class AntPathMatcher {
             patIdxEnd--;
             strIdxEnd--;
         }
-        if (strIdxStart > strIdxEnd) {
+        if ( strIdxStart > strIdxEnd ) {
             // All characters in the string are used. Check if only '*'s are
             // left in the pattern. If so, we succeeded. Otherwise failure.
-            for (int i = patIdxStart; i <= patIdxEnd; i++) {
-                if (patArr[i] != '*') {
+            for ( int i = patIdxStart; i <= patIdxEnd; i++ ) {
+                if ( patArr[ i ] != '*' ) {
                     return false;
                 }
             }
@@ -284,15 +273,15 @@ public class AntPathMatcher {
 
         // process pattern between stars. padIdxStart and patIdxEnd point
         // always to a '*'.
-        while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
+        while ( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd ) {
             int patIdxTmp = -1;
-            for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
-                if (patArr[i] == '*') {
+            for ( int i = patIdxStart + 1; i <= patIdxEnd; i++ ) {
+                if ( patArr[ i ] == '*' ) {
                     patIdxTmp = i;
                     break;
                 }
             }
-            if (patIdxTmp == patIdxStart + 1) {
+            if ( patIdxTmp == patIdxStart + 1 ) {
                 // Two stars next to each other, skip the first one.
                 patIdxStart++;
                 continue;
@@ -303,11 +292,11 @@ public class AntPathMatcher {
             int strLength = strIdxEnd - strIdxStart + 1;
             int foundIdx = -1;
             strLoop:
-            for (int i = 0; i <= strLength - patLength; i++) {
-                for (int j = 0; j < patLength; j++) {
-                    ch = patArr[patIdxStart + j + 1];
-                    if (ch != '?') {
-                        if (ch != strArr[strIdxStart + i + j]) {
+            for ( int i = 0; i <= strLength - patLength; i++ ) {
+                for ( int j = 0; j < patLength; j++ ) {
+                    ch = patArr[ patIdxStart + j + 1 ];
+                    if ( ch != '?' ) {
+                        if ( ch != strArr[ strIdxStart + i + j ] ) {
                             continue strLoop;
                         }
                     }
@@ -317,7 +306,7 @@ public class AntPathMatcher {
                 break;
             }
 
-            if (foundIdx == -1) {
+            if ( foundIdx == -1 ) {
                 return false;
             }
 
@@ -327,8 +316,8 @@ public class AntPathMatcher {
 
         // All characters in the string are used. Check if only '*'s are left
         // in the pattern. If so, we succeeded. Otherwise failure.
-        for (int i = patIdxStart; i <= patIdxEnd; i++) {
-            if (patArr[i] != '*') {
+        for ( int i = patIdxStart; i <= patIdxEnd; i++ ) {
+            if ( patArr[ i ] != '*' ) {
                 return false;
             }
         }
@@ -363,31 +352,32 @@ public class AntPathMatcher {
      * <code>pattern</code>' and '<code>path</code>', but does
      * <strong>not</strong> enforce this.
      */
-    public String extractPathWithinPattern(String pattern, String path) {
-        final String[] patternParts = tokenizeToStringArray(pattern, this.pathSeparator);
-        final String[] pathParts = tokenizeToStringArray(path, this.pathSeparator);
+    public String extractPathWithinPattern( String pattern,
+                                            String path ) {
+        final String[] patternParts = tokenizeToStringArray( pattern, this.pathSeparator );
+        final String[] pathParts = tokenizeToStringArray( path, this.pathSeparator );
 
         final StringBuilder buffer = new StringBuilder();
 
         // Add any path parts that have a wildcarded pattern part.
         int puts = 0;
-        for (int i = 0; i < patternParts.length; i++) {
-            final String patternPart = patternParts[i];
-            if ((patternPart.indexOf('*') > -1 || patternPart.indexOf('?') > -1) && pathParts.length >= i + 1) {
-                if (puts > 0 || (i == 0 && !pattern.startsWith(this.pathSeparator))) {
-                    buffer.append(this.pathSeparator);
+        for ( int i = 0; i < patternParts.length; i++ ) {
+            final String patternPart = patternParts[ i ];
+            if ( ( patternPart.indexOf( '*' ) > -1 || patternPart.indexOf( '?' ) > -1 ) && pathParts.length >= i + 1 ) {
+                if ( puts > 0 || ( i == 0 && !pattern.startsWith( this.pathSeparator ) ) ) {
+                    buffer.append( this.pathSeparator );
                 }
-                buffer.append(pathParts[i]);
+                buffer.append( pathParts[ i ] );
                 puts++;
             }
         }
 
         // Append any trailing path parts.
-        for (int i = patternParts.length; i < pathParts.length; i++) {
-            if (puts > 0 || i > 0) {
-                buffer.append(this.pathSeparator);
+        for ( int i = patternParts.length; i < pathParts.length; i++ ) {
+            if ( puts > 0 || i > 0 ) {
+                buffer.append( this.pathSeparator );
             }
-            buffer.append(pathParts[i]);
+            buffer.append( pathParts[ i ] );
         }
 
         return buffer.toString();
@@ -408,19 +398,20 @@ public class AntPathMatcher {
      * @see java.util.StringTokenizer
      * @see java.lang.String#trim()
      */
-    public static String[] tokenizeToStringArray(String str, String delimiters) {
-        if (str == null) {
+    public static String[] tokenizeToStringArray( String str,
+                                                  String delimiters ) {
+        if ( str == null ) {
             return null;
         }
-        final StringTokenizer st = new StringTokenizer(str, delimiters);
+        final StringTokenizer st = new StringTokenizer( str, delimiters );
         final List<String> tokens = new ArrayList<String>();
-        while (st.hasMoreTokens()) {
+        while ( st.hasMoreTokens() ) {
             final String token = st.nextToken().trim();
-            if (token.length() > 0) {
-                tokens.add(token);
+            if ( token.length() > 0 ) {
+                tokens.add( token );
             }
         }
-        return tokens.toArray(new String[tokens.size()]);
+        return tokens.toArray( new String[ tokens.size() ] );
     }
 
-}
+}
\ No newline at end of file

programming_language: Java
filename: AntPathMatcher.java
change_type: ModificationType.ADD
diff: @@ -0,0 +1,89 @@
+package org.uberfire.io.regex;
+
+import java.net.URI;
+import java.util.Collection;
+
+import org.uberfire.java.nio.file.Path;
+
+import static org.uberfire.commons.validation.Preconditions.*;
+
+public final class AntPathMatcher {
+
+    private static org.uberfire.commons.regex.util.AntPathMatcher matcher = new org.uberfire.commons.regex.util.AntPathMatcher();
+
+    public static boolean filter( final Collection<String> includes,
+                                  final Collection<String> excludes,
+                                  final Path path ) {
+        checkNotNull( "includes", includes );
+        checkNotNull( "excludes", excludes );
+        checkNotNull( "path", path );
+        if ( includes.isEmpty() && excludes.isEmpty() ) {
+            return true;
+        } else if ( includes.isEmpty() ) {
+            return !( excludes( excludes, path ) );
+        } else if ( excludes.isEmpty() ) {
+            return includes( includes, path );
+        }
+        return includes( includes, path ) && !( excludes( excludes, path ) );
+    }
+
+    public static boolean filter( final Collection<String> includes,
+                                  final Collection<String> excludes,
+                                  final URI uri ) {
+        checkNotNull( "includes", includes );
+        checkNotNull( "excludes", excludes );
+        checkNotNull( "uri", uri );
+        if ( includes.isEmpty() && excludes.isEmpty() ) {
+            return true;
+        } else if ( includes.isEmpty() ) {
+            return !( excludes( excludes, uri ) );
+        } else if ( excludes.isEmpty() ) {
+            return includes( includes, uri );
+        }
+        return includes( includes, uri ) && !( excludes( excludes, uri ) );
+    }
+
+    public static boolean includes( final Collection<String> patterns,
+                                    final Path path ) {
+        checkNotNull( "patterns", patterns );
+        checkNotNull( "path", path );
+        return matches( patterns, path );
+    }
+
+    public static boolean includes( final Collection<String> patterns,
+                                    final URI uri ) {
+        checkNotNull( "patterns", patterns );
+        checkNotNull( "uri", uri );
+        return matches( patterns, uri );
+    }
+
+    public static boolean excludes( final Collection<String> patterns,
+                                    final URI uri ) {
+        checkNotNull( "patterns", patterns );
+        checkNotNull( "uri", uri );
+        return matches( patterns, uri );
+    }
+
+    public static boolean excludes( final Collection<String> patterns,
+                                    final Path path ) {
+        checkNotNull( "patterns", patterns );
+        checkNotNull( "path", path );
+        return matches( patterns, path );
+    }
+
+    private static boolean matches( final Collection<String> patterns,
+                                    final Path path ) {
+        return matches( patterns, path.toUri() );
+    }
+
+    private static boolean matches( final Collection<String> patterns,
+                                    final URI uri ) {
+        for ( final String pattern : patterns ) {
+            if ( matcher.match( pattern, uri.toString() ) ) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+}

programming_language: C++
filename: AntPathMatcherTest.java
change_type: ModificationType.ADD
diff: @@ -0,0 +1,244 @@
+package org.uberfire.io.regex;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.uberfire.io.CommonIOServiceDotFileTest;
+import org.uberfire.io.IOService;
+import org.uberfire.io.impl.IOServiceDotFileImpl;
+import org.uberfire.java.nio.file.Path;
+import org.uberfire.java.nio.file.Paths;
+
+import static org.uberfire.io.regex.AntPathMatcher.*;
+
+public class AntPathMatcherTest {
+
+    final static IOService ioService = new IOServiceDotFileImpl();
+    private static File path = null;
+
+    @BeforeClass
+    public static void setup() throws IOException {
+        path = CommonIOServiceDotFileTest.createTempDirectory();
+        System.setProperty( "org.uberfire.nio.git.dir", path.getAbsolutePath() );
+        System.out.println( ".niogit: " + path.getAbsolutePath() );
+
+        final URI newRepo = URI.create( "git://antpathmatcher" );
+
+        ioService.newFileSystem( newRepo, new HashMap<String, Object>() );
+    }
+
+    @AfterClass
+    @BeforeClass
+    public static void cleanup() {
+        if ( path != null ) {
+            FileUtils.deleteQuietly( path );
+        }
+    }
+
+    @Test
+    public void testIncludes() {
+        final Collection<String> patterns = new ArrayList<String>() {{
+            add( "git://**" );
+            add( "**/repo/**" );
+        }};
+
+        {
+            final Path path = Paths.get( URI.create( "file:///Users/home" ) );
+            Assert.assertFalse( includes( patterns, path ) );
+        }
+
+        {
+            final Path path = Paths.get( URI.create( "git://antpathmatcher" ) );
+            Assert.assertTrue( includes( patterns, path ) );
+        }
+
+        {
+            final Path path = Paths.get( URI.create( "git://master@antpathmatcher" ) );
+            Assert.assertTrue( includes( patterns, path ) );
+        }
+    }
+
+    @Test
+    public void testIncludesMid() {
+        final Collection<String> patterns = new ArrayList<String>() {{
+            add( "default://**" );
+            add( "**/repo/**" );
+        }};
+
+        {
+            final Path path = Paths.get( URI.create( "file:///Users/home" ) );
+            Assert.assertTrue( includes( patterns, path ) );
+        }
+
+        {
+            final Path path = Paths.get( URI.create( "git://antpathmatcher" ) );
+            Assert.assertFalse( includes( patterns, path ) );
+        }
+
+        {
+            final Path path = Paths.get( URI.create( "git://master@antpathmatcher/repo/sss" ) );
+            Assert.assertTrue( includes( patterns, path ) );
+        }
+    }
+
+    @Test
+    public void testExcludes() {
+        final Collection<String> patterns = new ArrayList<String>() {{
+            add( "git://**" );
+            add( "**/repo/**" );
+        }};
+
+        {
+            final Path path = Paths.get( URI.create( "file:///Users/home" ) );
+            Assert.assertFalse( excludes( patterns, path ) );
+        }
+
+        {
+            final Path path = Paths.get( URI.create( "git://antpathmatcher" ) );
+            Assert.assertTrue( excludes( patterns, path ) );
+        }
+
+        {
+            final Path path = Paths.get( URI.create( "git://master@antpathmatcher" ) );
+            Assert.assertTrue( excludes( patterns, path ) );
+        }
+    }
+
+    @Test
+    public void testExcludesMid() {
+        final Collection<String> patterns = new ArrayList<String>() {{
+            add( "default://**" );
+            add( "**/repo/**" );
+        }};
+
+        {
+            final Path path = Paths.get( URI.create( "file:///Users/home" ) );
+            Assert.assertTrue( excludes( patterns, path ) );
+        }
+
+        {
+            final Path path = Paths.get( URI.create( "git://antpathmatcher" ) );
+            Assert.assertFalse( excludes( patterns, path ) );
+        }
+
+        {
+            final Path path = Paths.get( URI.create( "git://master@antpathmatcher/repo/sss" ) );
+            Assert.assertTrue( excludes( patterns, path ) );
+        }
+    }
+
+    @Test
+    public void testFilter() {
+        final Collection<String> includes = new ArrayList<String>() {{
+            add( "git://**" );
+        }};
+        final Collection<String> excludes = new ArrayList<String>() {{
+            add( "default://**" );
+        }};
+
+        {
+            final Path path = Paths.get( URI.create( "file:///Users/home" ) );
+            Assert.assertFalse( filter( includes, excludes, path ) );
+        }
+
+        {
+            final Path path = Paths.get( URI.create( "git://antpathmatcher" ) );
+            Assert.assertTrue( filter( includes, excludes, path ) );
+        }
+
+        {
+            final Path path = Paths.get( URI.create( "git://master@antpathmatcher/repo/sss" ) );
+            Assert.assertTrue( filter( includes, excludes, path ) );
+        }
+
+        Assert.assertTrue( filter( Collections.<String>emptyList(), Collections.<String>emptyList(), Paths.get( URI.create( "git://master@antpathmatcher/repo/sss" ) ) ) );
+        Assert.assertTrue( filter( Collections.<String>emptyList(), Collections.<String>emptyList(), Paths.get( URI.create( "git://antpathmatcher" ) ) ) );
+    }
+
+    @Test
+    public void testIncludesUri() {
+        final Collection<String> patterns = new ArrayList<String>() {{
+            add( "git://**" );
+            add( "**/repo/**" );
+        }};
+
+        Assert.assertFalse( includes( patterns, URI.create( "file:///Users/home" ) ) );
+
+        Assert.assertTrue( includes( patterns, URI.create( "git://antpathmatcher" ) ) );
+
+        Assert.assertTrue( includes( patterns, URI.create( "git://master@antpathmatcher" ) ) );
+    }
+
+    @Test
+    public void testIncludesMidUri() {
+        final Collection<String> patterns = new ArrayList<String>() {{
+            add( "file://**" );
+            add( "**/repo/**" );
+        }};
+
+        Assert.assertTrue( includes( patterns, URI.create( "file:///Users/home" ) ) );
+
+        Assert.assertFalse( includes( patterns, URI.create( "git://antpathmatcher" ) ) );
+
+        Assert.assertTrue( includes( patterns, URI.create( "git://master@antpathmatcher/repo/sss" ) ) );
+    }
+
+    @Test
+    public void testExcludesUri() {
+        final Collection<String> patterns = new ArrayList<String>() {{
+            add( "git://**" );
+            add( "**/repo/**" );
+        }};
+
+        Assert.assertFalse( excludes( patterns, URI.create( "file:///Users/home" ) ) );
+
+        Assert.assertTrue( excludes( patterns, URI.create( "git://antpathmatcher" ) ) );
+
+        Assert.assertTrue( excludes( patterns, URI.create( "git://master@antpathmatcher" ) ) );
+    }
+
+    @Test
+    public void testExcludesMidUri() {
+        final Collection<String> patterns = new ArrayList<String>() {{
+            add( "file://**" );
+            add( "**/repo/**" );
+        }};
+
+        Assert.assertTrue( excludes( patterns, URI.create( "file:///Users/home" ) ) );
+
+        Assert.assertFalse( excludes( patterns, URI.create( "git://antpathmatcher" ) ) );
+
+        Assert.assertTrue( excludes( patterns, URI.create( "git://master@antpathmatcher/repo/sss" ) ) );
+    }
+
+    @Test
+    public void testFilterUri() {
+        final Collection<String> includes = new ArrayList<String>() {{
+            add( "git://**" );
+        }};
+        final Collection<String> excludes = new ArrayList<String>() {{
+            add( "file://**" );
+        }};
+
+        Assert.assertFalse( filter( includes, excludes, URI.create( "file:///Users/home" ) ) );
+
+        Assert.assertTrue( filter( includes, excludes, URI.create( "git://antpathmatcher" ) ) );
+
+        Assert.assertTrue( filter( includes, excludes, URI.create( "git://master@antpathmatcher/repo/sss" ) ) );
+
+        Assert.assertTrue( filter( Collections.<String>emptyList(), Collections.<String>emptyList(), URI.create( "file:///Users/home" ) ) );
+
+        Assert.assertTrue( filter( Collections.<String>emptyList(), Collections.<String>emptyList(), URI.create( "git://master@antpathmatcher/repo/sss" ) ) );
+
+    }
+}

programming_language: Java
filename: URLResourceManager.java
change_type: ModificationType.MODIFY
diff: @@ -31,7 +31,7 @@ import org.uberfire.security.Resource;
 import org.uberfire.security.ResourceManager;
 import org.uberfire.security.Role;
 import org.uberfire.security.impl.RoleImpl;
-import org.uberfire.security.server.util.AntPathMatcher;
+import org.uberfire.commons.regex.util.AntPathMatcher;
 import org.yaml.snakeyaml.Yaml;
 
 import static java.util.Collections.*;

programming_language: Java
filename: BaseFilteredServlet.java
change_type: ModificationType.ADD
diff: @@ -0,0 +1,66 @@
+package org.uberfire.server;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.uberfire.io.regex.AntPathMatcher;
+import org.uberfire.java.nio.file.Path;
+
+import static javax.servlet.http.HttpServletResponse.*;
+
+public abstract class BaseFilteredServlet extends HttpServlet {
+
+    private static final Logger logger = LoggerFactory.getLogger( BaseFilteredServlet.class );
+
+    protected Collection<String> includes = new ArrayList<String>();
+    protected Collection<String> excludes = new ArrayList<String>();
+
+    @Override
+    public void init( final ServletConfig config ) throws ServletException {
+        final String _includes = config.getInitParameter( "includes-path" );
+        if ( _includes != null && !_includes.trim().isEmpty() ) {
+            includes.addAll( Arrays.asList( _includes.split( "," ) ) );
+        }
+        final String _excludes = config.getInitParameter( "excludes-path" );
+        if ( _excludes != null && !_excludes.trim().isEmpty() ) {
+            excludes.addAll( Arrays.asList( _excludes.split( "," ) ) );
+        }
+    }
+
+    protected boolean validateAccess( final URI uri,
+                                      final HttpServletResponse response ) {
+        if ( !AntPathMatcher.filter( includes, excludes, uri ) ) {
+            logger.error( "Invalid credentials to path." );
+            try {
+                response.sendError( SC_FORBIDDEN );
+            } catch ( Exception ex ) {
+                logger.error( ex.getMessage() );
+            }
+            return false;
+        }
+        return true;
+    }
+
+    protected boolean validateAccess( final Path path,
+                                      final HttpServletResponse response ) {
+        if ( !AntPathMatcher.filter( includes, excludes, path ) ) {
+            logger.error( "Invalid credentials to path." );
+            try {
+                response.sendError( SC_FORBIDDEN );
+            } catch ( Exception ex ) {
+                logger.error( ex.getMessage() );
+            }
+            return false;
+        }
+        return true;
+    }
+
+}

programming_language: Java
filename: FileDownloadServlet.java
change_type: ModificationType.MODIFY
diff: @@ -2,11 +2,9 @@ package org.uberfire.server;
 
 import java.io.IOException;
 import java.net.URI;
-import java.net.URISyntaxException;
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -15,37 +13,46 @@ import org.slf4j.LoggerFactory;
 import org.uberfire.io.IOService;
 import org.uberfire.java.nio.file.Path;
 
+import static java.lang.String.*;
+
 public class FileDownloadServlet
-        extends HttpServlet {
+        extends BaseFilteredServlet {
 
-    private static final Logger logger = LoggerFactory.getLogger(FileDownloadServlet.class);
+    private static final Logger logger = LoggerFactory.getLogger( FileDownloadServlet.class );
 
     @Inject
     @Named("ioStrategy")
     private IOService ioService;
 
     @Override
-    protected void doGet(HttpServletRequest request, HttpServletResponse response)
+    protected void doGet( HttpServletRequest request,
+                          HttpServletResponse response )
             throws ServletException, IOException {
 
         try {
 
-            Path path = ioService.get(new URI(request.getParameter("path")));
+            final URI uri = new URI( request.getParameter( "path" ) );
+
+            if ( !validateAccess( uri, response ) ) {
+                return;
+            }
+
+            final Path path = ioService.get( uri );
 
-            byte[] bytes = ioService.readAllBytes(path);
+            byte[] bytes = ioService.readAllBytes( path );
 
-            response.setHeader("Content-Disposition",
-                    String.format("attachment; filename=%s;", path.getFileName().toString()));
+            response.setHeader( "Content-Disposition",
+                                format( "attachment; filename=%s;", path.getFileName().toString() ) );
 
-            response.setContentType("application/octet-stream");
+            response.setContentType( "application/octet-stream" );
 
             response.getOutputStream().write(
                     bytes,
                     0,
-                    bytes.length);
+                    bytes.length );
 
-        } catch (URISyntaxException e) {
-            logger.error("Failed to download a file.", e);
+        } catch ( final Exception e ) {
+            logger.error( "Failed to download a file.", e );
         }
 
     }

programming_language: Java
filename: FileUploadServlet.java
change_type: ModificationType.MODIFY
diff: @@ -7,7 +7,6 @@ import java.util.Iterator;
 import javax.inject.Inject;
 import javax.inject.Named;
 import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
@@ -23,73 +22,90 @@ import org.uberfire.io.IOService;
 import org.uberfire.java.nio.file.Path;
 
 public class FileUploadServlet
-        extends HttpServlet {
+        extends BaseFilteredServlet {
 
-    private static final Logger logger = LoggerFactory.getLogger(FileUploadServlet.class);
+    private static final Logger logger = LoggerFactory.getLogger( FileUploadServlet.class );
 
     @Inject
     @Named("ioStrategy")
     private IOService ioService;
 
     @Override
-    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
+    protected void doPost( HttpServletRequest request,
+                           HttpServletResponse response ) throws ServletException, IOException {
 
         try {
-            if (request.getParameter("path") != null) {
-                writeFile(ioService.get(new URI(request.getParameter("path"))), getFileItem(request));
+            if ( request.getParameter( "path" ) != null ) {
+
+                final URI uri = new URI( request.getParameter( "path" ) );
+
+                if ( !validateAccess( uri, response ) ) {
+                    return;
+                }
+
+                writeFile( ioService.get( uri ), getFileItem( request ) );
+
+                writeResponse( response, "OK" );
+            } else if ( request.getParameter( "folder" ) != null ) {
+
+                final URI uri = new URI( request.getParameter( "folder" ) + "/" + request.getParameter( "fileName" ) );
+
+                if ( !validateAccess( uri, response ) ) {
+                    return;
+                }
 
-                writeResponse(response, "OK");
-            } else if (request.getParameter("folder") != null) {
                 writeFile(
-                        ioService.get(new URI(request.getParameter("folder") + "/" + request.getParameter("fileName"))),
-                        getFileItem(request));
+                        ioService.get( uri ),
+                        getFileItem( request ) );
 
-                writeResponse(response, "OK");
+                writeResponse( response, "OK" );
             }
 
-        } catch (FileUploadException e) {
-            logError(e);
-            writeResponse(response, "FAIL");
-        } catch (URISyntaxException e) {
-            logError(e);
-            writeResponse(response, "FAIL");
+        } catch ( FileUploadException e ) {
+            logError( e );
+            writeResponse( response, "FAIL" );
+        } catch ( URISyntaxException e ) {
+            logError( e );
+            writeResponse( response, "FAIL" );
         }
     }
 
-    private FileItem getFileItem(HttpServletRequest request) throws FileUploadException {
-        Iterator iterator = getServletFileUpload().parseRequest(request).iterator();
-        while (iterator.hasNext()) {
+    private FileItem getFileItem( HttpServletRequest request ) throws FileUploadException {
+        Iterator iterator = getServletFileUpload().parseRequest( request ).iterator();
+        while ( iterator.hasNext() ) {
             FileItem item = (FileItem) iterator.next();
-            if (!item.isFormField()) {
+            if ( !item.isFormField() ) {
                 return item;
             }
         }
         return null;
     }
 
-    private void writeResponse(HttpServletResponse response, String ok) throws IOException {
-        response.setContentType("text/html");
-        response.getWriter().write(ok);
+    private void writeResponse( HttpServletResponse response,
+                                String ok ) throws IOException {
+        response.setContentType( "text/html" );
+        response.getWriter().write( ok );
     }
 
     private ServletFileUpload getServletFileUpload() {
         FileItemFactory factory = new DiskFileItemFactory();
-        ServletFileUpload upload = new ServletFileUpload(factory);
-        upload.setHeaderEncoding("UTF-8");
+        ServletFileUpload upload = new ServletFileUpload( factory );
+        upload.setHeaderEncoding( "UTF-8" );
         return upload;
     }
 
-    private void writeFile(Path path, FileItem uploadedItem) throws IOException {
-        if (!ioService.exists(path)) {
-            ioService.createFile(path);
+    private void writeFile( Path path,
+                            FileItem uploadedItem ) throws IOException {
+        if ( !ioService.exists( path ) ) {
+            ioService.createFile( path );
         }
 
-        ioService.write(path, IOUtils.toByteArray(uploadedItem.getInputStream()));
+        ioService.write( path, IOUtils.toByteArray( uploadedItem.getInputStream() ) );
 
         uploadedItem.getInputStream().close();
     }
 
-    private void logError(Throwable e) {
-        logger.error("Failed to upload a file.", e);
+    private void logError( Throwable e ) {
+        logger.error( "Failed to upload a file.", e );
     }
 }

programming_language: Java