@@ -254,7 +254,7 @@ public static void setSchemaValidation(boolean enable) {
254
254
}
255
255
256
256
/**
257
- * This retrieves a Policy based on a default location ("resources/antisamy.xml")
257
+ * Construct a Policy using the default policy file location ("resources/antisamy.xml").
258
258
*
259
259
* @return A populated Policy object based on the XML policy file located in the default location.
260
260
* @throws PolicyException If the file is not found or there is a problem parsing the file.
@@ -264,7 +264,7 @@ public static Policy getInstance() throws PolicyException {
264
264
}
265
265
266
266
/**
267
- * This retrieves a Policy based on the file name passed in
267
+ * Construct a Policy based on the file whose name is passed in.
268
268
*
269
269
* @param filename The path to the XML policy file.
270
270
* @return A populated Policy object based on the XML policy file located in the location passed in.
@@ -276,9 +276,9 @@ public static Policy getInstance(String filename) throws PolicyException {
276
276
}
277
277
278
278
/**
279
- * This retrieves a Policy based on the InputStream object passed in
279
+ * Construct a Policy from the InputStream object passed in.
280
280
*
281
- * @param inputStream An InputStream which contains thhe XML policy information.
281
+ * @param inputStream An InputStream which contains the XML policy information.
282
282
* @return A populated Policy object based on the XML policy file pointed to by the inputStream parameter.
283
283
* @throws PolicyException If there is a problem parsing the input stream.
284
284
*/
@@ -287,11 +287,11 @@ public static Policy getInstance(InputStream inputStream) throws PolicyException
287
287
// If schema validation is disabled, we elevate this msg to the warn level to match the
288
288
// level of the mandatory warning that will follow. We do the same below.
289
289
if (validateSchema ) logger .info (logMsg ); else logger .warn (logMsg );
290
- return new InternalPolicy (null , getSimpleParseContext (getTopLevelElement (inputStream )));
290
+ return new InternalPolicy (getSimpleParseContext (getTopLevelElement (inputStream )));
291
291
}
292
292
293
293
/**
294
- * This retrieves a Policy based on the File object passed in
294
+ * Construct a Policy from the File object passed in.
295
295
*
296
296
* @param file A File object which contains the XML policy information.
297
297
* @return A populated Policy object based on the XML policy file pointed to by the File parameter.
@@ -307,10 +307,17 @@ public static Policy getInstance(File file) throws PolicyException {
307
307
}
308
308
309
309
/**
310
- * This retrieves a Policy based on the URL object passed in.
310
+ * Construct a Policy from the target of the URL passed in.
311
311
* <br><br>
312
312
* NOTE: This is the only factory method that will work with <include> tags
313
313
* in AntiSamy policy files.
314
+ * <br><br>
315
+ * For security reasons, the provided URL must point to a local file. Currently only 'file:' and 'jar:'
316
+ * URL prefixes are allowed. If you want to use a different URL format, and are confident that the URL
317
+ * points to a safe source, you can open the target of the URL with URL.openStream(), and use the
318
+ * getInstance(InputStream) constructor instead. For example, Spring has classpath: and Wildfly/Jboss
319
+ * supports vfs: for accessing local files. Just be aware that this alternate constructor doesn't support
320
+ * the use of <include> tags, per the NOTE above.
314
321
*
315
322
* @param url A URL object which contains the XML policy information.
316
323
* @return A populated Policy object based on the XML policy file pointed to by the File parameter.
@@ -319,7 +326,7 @@ public static Policy getInstance(File file) throws PolicyException {
319
326
public static Policy getInstance (URL url ) throws PolicyException {
320
327
String logMsg = "Attempting to load AntiSamy policy from URL: " + url .toString ();
321
328
if (validateSchema ) logger .info (logMsg ); else logger .warn (logMsg );
322
- return new InternalPolicy (url , getParseContext (getTopLevelElement (url ), url ));
329
+ return new InternalPolicy (getParseContext (getTopLevelElement (url ), url ));
323
330
}
324
331
325
332
protected Policy (ParseContext parseContext ) throws PolicyException {
@@ -438,7 +445,7 @@ protected static Element getTopLevelElement(InputSource source, Callable<InputSo
438
445
thrownException = e ;
439
446
throw new PolicyException (e );
440
447
} finally {
441
- if (!validateSchema && ( thrownException == null ) ) {
448
+ if (!validateSchema && thrownException == null ) {
442
449
// We warn when the policy has a valid schema, but schema validation is disabled.
443
450
logger .warn ("XML schema validation is disabled for a valid AntiSamy policy. Please reenable policy validation." );
444
451
}
@@ -542,7 +549,7 @@ private static Element getPolicy(String href, URL baseUrl) throws PolicyExceptio
542
549
thrownException = e ;
543
550
throw new PolicyException (e );
544
551
} finally {
545
- if (!validateSchema && ( thrownException == null ) ) {
552
+ if (!validateSchema && thrownException == null ) {
546
553
// We warn when the policy has a valid schema, but schema validation is disabled.
547
554
logger .warn ("XML schema validation is disabled for a valid AntiSamy policy. Please reenable policy validation." );
548
555
}
@@ -561,10 +568,7 @@ private static Element getDocumentElementByUrl(String href, URL baseUrl, boolean
561
568
// system id, since we have a base URI.
562
569
if (href != null && baseUrl != null ) {
563
570
564
- if (!"file" .equals (baseUrl .getProtocol ())) {
565
- throw new MalformedURLException (
566
- "Only local files can be accessed with the baseURL. Illegal value supplied was: " + baseUrl );
567
- }
571
+ verifyLocalUrl (baseUrl );
568
572
569
573
URL url ;
570
574
@@ -1007,10 +1011,7 @@ public static InputSource resolveEntity(final String systemId, URL baseUrl) thro
1007
1011
// system id, since we have a base URI.
1008
1012
if (systemId != null && baseUrl != null ) {
1009
1013
1010
- if (!"file" .equals (baseUrl .getProtocol ())) {
1011
- throw new MalformedURLException (
1012
- "Only local files can be accessed with the baseURL. Illegal value supplied was: " + baseUrl );
1013
- }
1014
+ verifyLocalUrl (baseUrl );
1014
1015
1015
1016
URL url ;
1016
1017
@@ -1019,7 +1020,7 @@ public static InputSource resolveEntity(final String systemId, URL baseUrl) thro
1019
1020
source = new InputSource (url .openStream ());
1020
1021
source .setSystemId (systemId );
1021
1022
return source ;
1022
- } catch (MalformedURLException | java . io . FileNotFoundException e ) {
1023
+ } catch (MalformedURLException | FileNotFoundException e ) {
1023
1024
try {
1024
1025
String absURL = URIUtils .resolveAsString (systemId , baseUrl .toString ());
1025
1026
url = new URL (absURL );
@@ -1037,6 +1038,24 @@ public static InputSource resolveEntity(final String systemId, URL baseUrl) thro
1037
1038
return null ;
1038
1039
}
1039
1040
1041
+ /**
1042
+ * Verify that the target of the URL is a local file only. Currently, we allow file: and jar: URLs.
1043
+ * The target of the URL is typically an AntiSamy policy file.
1044
+ * @param url The URL to verify.
1045
+ * @throws MalformedURLException If the supplied URL does not reference a local file directly, or one inside
1046
+ * a local JAR file.
1047
+ */
1048
+ private static void verifyLocalUrl (URL url ) throws MalformedURLException {
1049
+
1050
+ switch (url .getProtocol ()) {
1051
+ case "file" :
1052
+ case "jar" : break ; // These are OK.
1053
+
1054
+ default : throw new MalformedURLException (
1055
+ "Only local files can be accessed with a policy URL. Illegal value supplied was: " + url );
1056
+ }
1057
+ }
1058
+
1040
1059
private static Element getFirstChild (Element element , String tagName ) {
1041
1060
if (element == null ) return null ;
1042
1061
NodeList elementsByTagName = element .getElementsByTagName (tagName );
0 commit comments