@@ -32,6 +32,9 @@ public class Utils {
3232
3333 public static final String FILE_PROTOCOL = "file" ;
3434 public static final String CLASSPATH_PROTOCOL = "classpath" ;
35+ // Special marker to indicate we want to allow remote files such as
36+ // Windows UNC, etc
37+ public static final String REMOTE_FILE_PROTOCOL = "remote-" + FILE_PROTOCOL ;
3538
3639 public static Resource resourceFromString (String uri ) throws MalformedURLException {
3740 // default allows all
@@ -49,7 +52,7 @@ public static Resource resourceFromString(String uri, Set<String> allowedProtoco
4952 // First, just try and load a local file (if it exists) and if "file"
5053 // as part of the allow list. This preserves previous behavior of
5154 // always optimistically trying a local file first.
52- if (isAllowFile (allowedProtocols ) && new File (uri ).exists ()) {
55+ if (isAllowFile (allowedProtocols , uri ) && new File (uri ).exists ()) {
5356 resource = new FileSystemResource (uri );
5457 // If file isn't allowed, or if the file can't be found then check
5558 // if the string is a valid URL. If it's valid, then we need
@@ -71,28 +74,57 @@ public static Resource resourceFromString(String uri, Set<String> allowedProtoco
7174 // Catch all fail-safe if nothing else matches. This could happen if file is allowed
7275 // but not classpath but the file doesn't exist
7376 } else {
74- throw new IllegalArgumentException ("URL [" + uri + "] can't be found or is not allowed "
75- + " for loading resources" );
77+ throw new IllegalArgumentException ("URL [" + uri + "] can't be found or the protocol "
78+ + " is not allowed for loading resources" );
7679 }
7780 return resource ;
7881 }
7982
80- static boolean isAllowFile (Set <String > allowedProtocols ) {
81- return allowedProtocols == null || allowedProtocols .contains (FILE_PROTOCOL );
83+ // These method treats local files and remote files (that are pre-fixed
84+ // with two forward/backward slashes) differently
85+ static boolean isAllowFile (Set <String > allowedProtocols , String uri ) {
86+ if (allowedProtocols == null ) {
87+ return true ;
88+ }
89+ return isUnqualifiedRemoteFile (uri ) ? allowedProtocols .contains (REMOTE_FILE_PROTOCOL ) :
90+ allowedProtocols .contains (FILE_PROTOCOL );
8291 }
8392
8493 static boolean isAllowClasspath (Set <String > allowedProtocols ) {
8594 return allowedProtocols == null || allowedProtocols .contains (CLASSPATH_PROTOCOL );
8695 }
8796
88- private static void validateUrlAllowed (String uriString , Set <String > allowedProtocols )
97+ static void validateUrlAllowed (String uriString , Set <String > allowedProtocols )
8998 throws URISyntaxException {
9099 // Use new URI() to get the scheme
91100 // This is important because ResourceUtils.getURL() actually searches
92101 // the classpath which we don't want to do if not allowed
93- if (allowedProtocols != null && !allowedProtocols .contains (new URI (uriString ).getScheme ())) {
94- throw new IllegalArgumentException ("URL [" + uriString +
95- "] does not use an allowed protocol for loading URL resources" );
102+ if (allowedProtocols != null ) {
103+ final String detectedProtocol = getProtocolFromScheme (uriString );
104+ if (detectedProtocol == null ) {
105+ throw new IllegalArgumentException ("Could not detect protocol in given URI [" + uriString + "]" );
106+ }
107+ if (!allowedProtocols .contains (detectedProtocol )){
108+ throw new IllegalArgumentException ("URL [" + uriString +
109+ "] uses protocol '" + detectedProtocol + "' which is not allowed "
110+ + "for loading URL resources" );
111+ }
96112 }
97113 }
114+
115+ // If this is a qualified remote file then we return a special marker
116+ // so that we know this is trying to access a remote resource as that will be
117+ // validated differently
118+ private static String getProtocolFromScheme (String uriString ) throws URISyntaxException {
119+ return isQualifiedRemoteFile (uriString ) ? REMOTE_FILE_PROTOCOL :
120+ new URI (uriString ).getScheme ();
121+ }
122+
123+ private static boolean isUnqualifiedRemoteFile (String uri ) {
124+ return uri .startsWith ("//" ) || uri .startsWith ("\\ \\ " );
125+ }
126+
127+ private static boolean isQualifiedRemoteFile (String uri ) {
128+ return uri .startsWith (FILE_PROTOCOL + "://" ) || uri .startsWith (FILE_PROTOCOL + ":\\ \\ " );
129+ }
98130}
0 commit comments