Skip to content

Commit de03e06

Browse files
authored
Merge pull request #83 from nahsra/1.6.3
1.6.3
2 parents 73156b7 + 900a820 commit de03e06

File tree

9 files changed

+152
-74
lines changed

9 files changed

+152
-74
lines changed

pom.xml

+23-4
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<groupId>org.owasp.antisamy</groupId>
44
<artifactId>antisamy</artifactId>
55
<packaging>jar</packaging>
6-
<version>1.6.2</version>
6+
<version>1.6.3</version>
77
<distributionManagement>
88
<snapshotRepository>
99
<id>ossrh</id>
@@ -42,10 +42,10 @@
4242

4343
<properties>
4444
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
45-
<project.build.outputTimestamp>2021-18-03T18:02:00Z</project.build.outputTimestamp>
45+
<project.build.outputTimestamp>2021-08-04T01:37:00Z</project.build.outputTimestamp>
4646
<gpg.skip>true</gpg.skip><!-- by default skip gpg -->
4747
<version.slf4j>1.7.30</version.slf4j>
48-
<version.spotbugs.maven>4.2.0</version.spotbugs.maven>
48+
<version.spotbugs.maven>4.2.2</version.spotbugs.maven>
4949
<version.spotbugs>4.2.2</version.spotbugs>
5050
</properties>
5151

@@ -239,6 +239,9 @@
239239
<ignoredScopes>test</ignoredScopes>
240240
<message>Dependencies shouldn't require Java 8+.</message>
241241
</enforceBytecodeVersion>
242+
<requireMavenVersion>
243+
<version>3.2.5</version>
244+
</requireMavenVersion>
242245
</rules>
243246
<fail>true</fail>
244247
</configuration>
@@ -330,7 +333,13 @@
330333
<plugin>
331334
<groupId>org.cyclonedx</groupId>
332335
<artifactId>cyclonedx-maven-plugin</artifactId>
333-
<version>2.3.0</version>
336+
<version>2.4.0</version>
337+
<executions>
338+
<execution>
339+
<phase>package</phase>
340+
<goals><goal>makeBom</goal></goals>
341+
</execution>
342+
</executions>
334343
</plugin>
335344
<plugin>
336345
<groupId>com.github.spotbugs</groupId>
@@ -367,6 +376,16 @@
367376
<groupId>org.apache.maven.plugins</groupId>
368377
<artifactId>maven-javadoc-plugin</artifactId>
369378
</plugin>
379+
<plugin>
380+
<groupId>org.apache.maven.plugins</groupId>
381+
<artifactId>maven-pmd-plugin</artifactId>
382+
<version>3.14.0</version>
383+
<configuration>
384+
<targetJdk>1.7</targetJdk>
385+
<sourceEncoding>utf-8</sourceEncoding>
386+
<!-- excludeFromFailureFile>exclude-pmd.properties</excludeFromFailureFile -->
387+
</configuration>
388+
</plugin>
370389
<plugin>
371390
<groupId>org.apache.maven.plugins</groupId>
372391
<artifactId>maven-project-info-reports-plugin</artifactId>

src/main/java/org/owasp/validator/css/CssHandler.java

+1
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,7 @@ public void property(String name, LexicalUnit value, boolean important)
498498
styleSheet.append(validator.lexicalValueToString(value));
499499
value = value.getNextLexicalUnit();
500500
}
501+
if (important) { styleSheet.append(" !important"); }
501502
styleSheet.append(';');
502503
if (!isInline) { styleSheet.append('\n'); }
503504

src/main/java/org/owasp/validator/html/InternalPolicy.java

+7-9
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,12 @@
22

33
import org.owasp.validator.html.model.Tag;
44

5-
import java.net.URL;
65
import java.util.Map;
76

87
/**
98
* Contains a bunch of optimized lookups over the regular Policy Class. For internal use only.
109
*
11-
* Not part of any public api and may explode or self destruct at any given moment, preferably both.
10+
* Not part of any public API and may explode or self-destruct at any given moment, preferably both.
1211
*
1312
* @author Kristian Rosenvold
1413
*/
@@ -31,7 +30,7 @@ public class InternalPolicy extends Policy {
3130
private final boolean allowDynamicAttributes;
3231

3332

34-
protected InternalPolicy(URL baseUrl, ParseContext parseContext) throws PolicyException {
33+
protected InternalPolicy(ParseContext parseContext) throws PolicyException {
3534
super(parseContext);
3635
this.maxInputSize = determineMaxInputSize();
3736
this.isNofollowAnchors = isTrue(Policy.ANCHORS_NOFOLLOW);
@@ -41,8 +40,8 @@ protected InternalPolicy(URL baseUrl, ParseContext parseContext) throws PolicyEx
4140
this.omitXmlDeclaration = isTrue(Policy.OMIT_XML_DECLARATION);
4241
this.omitDoctypeDeclaration = isTrue(Policy.OMIT_DOCTYPE_DECLARATION);
4342
this.entityEncodeIntlCharacters = isTrue(Policy.ENTITY_ENCODE_INTL_CHARS);
44-
useXhtml = isTrue(Policy.USE_XHTML);
45-
embedTag = getTagByLowercaseName("embed");
43+
this.useXhtml = isTrue(Policy.USE_XHTML);
44+
this.embedTag = getTagByLowercaseName("embed");
4645
this.onUnknownTag = getDirective("onUnknownTag");
4746
this.isEncodeUnknownTag = "encode".equals(onUnknownTag);
4847
this.preserveComments = isTrue(Policy.PRESERVE_COMMENTS);
@@ -61,8 +60,8 @@ protected InternalPolicy(Policy old, Map<String, String> directives, Map<String,
6160
this.omitXmlDeclaration = isTrue(Policy.OMIT_XML_DECLARATION);
6261
this.omitDoctypeDeclaration = isTrue(Policy.OMIT_DOCTYPE_DECLARATION);
6362
this.entityEncodeIntlCharacters = isTrue(Policy.ENTITY_ENCODE_INTL_CHARS);
64-
useXhtml = isTrue(Policy.USE_XHTML);
65-
embedTag = getTagByLowercaseName("embed");
63+
this.useXhtml = isTrue(Policy.USE_XHTML);
64+
this.embedTag = getTagByLowercaseName("embed");
6665
this.onUnknownTag = getDirective("onUnknownTag");
6766
this.isEncodeUnknownTag = "encode".equals(onUnknownTag);
6867
this.preserveComments = isTrue(Policy.PRESERVE_COMMENTS);
@@ -127,7 +126,6 @@ private boolean isTrue(String anchorsNofollow) {
127126
return "true".equals(getDirective(anchorsNofollow));
128127
}
129128

130-
131129
public String getOnUnknownTag() {
132130
return onUnknownTag;
133131
}
@@ -144,7 +142,7 @@ public boolean isAllowDynamicAttributes() {
144142
* Returns the maximum input size. If this value is not specified by
145143
* the policy, the <code>DEFAULT_MAX_INPUT_SIZE</code> is used.
146144
*
147-
* @return the maximium input size.
145+
* @return the maximum input size.
148146
*/
149147
public int determineMaxInputSize() {
150148
int maxInputSize = Policy.DEFAULT_MAX_INPUT_SIZE;

src/main/java/org/owasp/validator/html/Policy.java

+38-19
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ public static void setSchemaValidation(boolean enable) {
254254
}
255255

256256
/**
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").
258258
*
259259
* @return A populated Policy object based on the XML policy file located in the default location.
260260
* @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 {
264264
}
265265

266266
/**
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.
268268
*
269269
* @param filename The path to the XML policy file.
270270
* @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 {
276276
}
277277

278278
/**
279-
* This retrieves a Policy based on the InputStream object passed in
279+
* Construct a Policy from the InputStream object passed in.
280280
*
281-
* @param inputStream An InputStream which contains thhe XML policy information.
281+
* @param inputStream An InputStream which contains the XML policy information.
282282
* @return A populated Policy object based on the XML policy file pointed to by the inputStream parameter.
283283
* @throws PolicyException If there is a problem parsing the input stream.
284284
*/
@@ -287,11 +287,11 @@ public static Policy getInstance(InputStream inputStream) throws PolicyException
287287
// If schema validation is disabled, we elevate this msg to the warn level to match the
288288
// level of the mandatory warning that will follow. We do the same below.
289289
if (validateSchema) logger.info(logMsg); else logger.warn(logMsg);
290-
return new InternalPolicy(null, getSimpleParseContext(getTopLevelElement(inputStream)));
290+
return new InternalPolicy(getSimpleParseContext(getTopLevelElement(inputStream)));
291291
}
292292

293293
/**
294-
* This retrieves a Policy based on the File object passed in
294+
* Construct a Policy from the File object passed in.
295295
*
296296
* @param file A File object which contains the XML policy information.
297297
* @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 {
307307
}
308308

309309
/**
310-
* This retrieves a Policy based on the URL object passed in.
310+
* Construct a Policy from the target of the URL passed in.
311311
* <br><br>
312312
* NOTE: This is the only factory method that will work with &lt;include&gt; tags
313313
* 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 &lt;include&gt; tags, per the NOTE above.
314321
*
315322
* @param url A URL object which contains the XML policy information.
316323
* @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 {
319326
public static Policy getInstance(URL url) throws PolicyException {
320327
String logMsg = "Attempting to load AntiSamy policy from URL: " + url.toString();
321328
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));
323330
}
324331

325332
protected Policy(ParseContext parseContext) throws PolicyException {
@@ -438,7 +445,7 @@ protected static Element getTopLevelElement(InputSource source, Callable<InputSo
438445
thrownException = e;
439446
throw new PolicyException(e);
440447
} finally {
441-
if (!validateSchema && (thrownException == null)) {
448+
if (!validateSchema && thrownException == null) {
442449
// We warn when the policy has a valid schema, but schema validation is disabled.
443450
logger.warn("XML schema validation is disabled for a valid AntiSamy policy. Please reenable policy validation.");
444451
}
@@ -542,7 +549,7 @@ private static Element getPolicy(String href, URL baseUrl) throws PolicyExceptio
542549
thrownException = e;
543550
throw new PolicyException(e);
544551
} finally {
545-
if (!validateSchema && (thrownException == null)) {
552+
if (!validateSchema && thrownException == null) {
546553
// We warn when the policy has a valid schema, but schema validation is disabled.
547554
logger.warn("XML schema validation is disabled for a valid AntiSamy policy. Please reenable policy validation.");
548555
}
@@ -561,10 +568,7 @@ private static Element getDocumentElementByUrl(String href, URL baseUrl, boolean
561568
// system id, since we have a base URI.
562569
if (href != null && baseUrl != null) {
563570

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);
568572

569573
URL url;
570574

@@ -1007,10 +1011,7 @@ public static InputSource resolveEntity(final String systemId, URL baseUrl) thro
10071011
// system id, since we have a base URI.
10081012
if (systemId != null && baseUrl != null) {
10091013

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);
10141015

10151016
URL url;
10161017

@@ -1019,7 +1020,7 @@ public static InputSource resolveEntity(final String systemId, URL baseUrl) thro
10191020
source = new InputSource(url.openStream());
10201021
source.setSystemId(systemId);
10211022
return source;
1022-
} catch (MalformedURLException | java.io.FileNotFoundException e) {
1023+
} catch (MalformedURLException | FileNotFoundException e) {
10231024
try {
10241025
String absURL = URIUtils.resolveAsString(systemId, baseUrl.toString());
10251026
url = new URL(absURL);
@@ -1037,6 +1038,24 @@ public static InputSource resolveEntity(final String systemId, URL baseUrl) thro
10371038
return null;
10381039
}
10391040

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+
10401059
private static Element getFirstChild(Element element, String tagName) {
10411060
if (element == null) return null;
10421061
NodeList elementsByTagName = element.getElementsByTagName(tagName);

src/main/java/org/owasp/validator/html/scan/MagicSAXFilter.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2007-2020, Arshan Dabirsiaghi, Jason Li
2+
* Copyright (c) 2007-2021, Arshan Dabirsiaghi, Jason Li
33
*
44
* All rights reserved.
55
*
@@ -58,7 +58,7 @@
5858
@SuppressFBWarnings(value = "REDOS", justification="Tested the Regex against saferegex and safe-regex and not vulnerable")
5959
public class MagicSAXFilter extends DefaultFilter implements XMLDocumentFilter {
6060

61-
private static enum Ops {
61+
private enum Ops {
6262
CSS, FILTER, REMOVE, TRUNCATE, KEEP, ENCODE
6363
}
6464
private final Stack<Ops> operations = new Stack<Ops>();
@@ -97,7 +97,7 @@ public void reset(InternalPolicy instance){
9797
}
9898

9999
public void characters(XMLString text, Augmentations augs) throws XNIException {
100-
//noinspection StatementWithEmptyBody
100+
101101
Ops topOp = peekTop();
102102
//noinspection StatementWithEmptyBody
103103
if (topOp == Ops.REMOVE) {
@@ -319,15 +319,13 @@ public void startElement(QName element, XMLAttributes attributes, Augmentations
319319
isValid = true;
320320
}
321321

322-
323322
if (!isValid) {
324323
isValid = attribute.matchesAllowedExpression(value);
325324
if (isValid) {
326325
validattributes.addAttribute(makeSimpleQname(name), "CDATA", value);
327326
}
328327
}
329328

330-
331329
// if value or regexp matched, attribute is already
332330
// copied, but what happens if not
333331
if (!isValid && "removeTag".equals(attribute.getOnInvalid())) {

src/test/java/org/owasp/validator/html/test/AntiSamyTest.java

+11
Original file line numberDiff line numberDiff line change
@@ -1479,5 +1479,16 @@ public void testGithubIssue62() {
14791479
fail(exc.getMessage());
14801480
}
14811481
}
1482+
1483+
@Test
1484+
public void testGithubIssue81() throws ScanException, PolicyException {
1485+
// Concern is that "!important" is missing after processing CSS
1486+
assertThat(as.scan("<p style=\"color: red !important\">Some Text</p>", policy, AntiSamy.DOM).getCleanHTML(), containsString("!important"));
1487+
assertThat(as.scan("<p style=\"color: red !important\">Some Text</p>", policy, AntiSamy.SAX).getCleanHTML(), containsString("!important"));
1488+
1489+
// Just to check scan keeps working accordingly without "!important"
1490+
assertThat(as.scan("<p style=\"color: red\">Some Text</p>", policy, AntiSamy.DOM).getCleanHTML(), not(containsString("!important")));
1491+
assertThat(as.scan("<p style=\"color: red\">Some Text</p>", policy, AntiSamy.SAX).getCleanHTML(), not(containsString("!important")));
1492+
}
14821493
}
14831494

0 commit comments

Comments
 (0)