Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Escape user-supplied values when setting build description #146

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,21 @@
<artifactId>apache-httpcomponents-client-4-api</artifactId>
<version>4.5.5-3.0</version>
</dependency>
<dependency>
<groupId>org.owasp.esapi</groupId>
<artifactId>esapi</artifactId>
<version>2.2.0.0</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are using slf4j-api for poll logging. Dependency management should be preferred over exclusion.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried that and I don't like the result. Essentially we would promise the code that it would find httpclient 4.5.8 and slf4j 1.7.26 on the server, which is not true. Or we would have to bundle those versions, which would bloat the hpi even more.

</exclusion>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package stashpullrequestbuilder.stashpullrequestbuilder;

import hudson.model.Cause;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.TreeMap;
import org.owasp.esapi.Encoder;
import org.owasp.esapi.reference.DefaultEncoder;

/** Created by Nathan McCarthy */
public class StashCause extends Cause {
Expand Down Expand Up @@ -123,18 +127,38 @@ public Map<String, String> getEnvironmentVariables() {

@Override
public String getShortDescription() {
return "<a href=\""
+ stashHost
+ "/projects/"
+ this.getDestinationRepositoryOwner()
+ "/repos/"
+ this.getDestinationRepositoryName()
+ "/pull-requests/"
+ this.getPullRequestId()
+ "\" >PR #"
+ this.getPullRequestId()
+ " "
+ this.getPullRequestTitle()
+ " </a>";
return "<a href='" + getEscapedUrl() + "'>" + getEscapedDescription() + " </a>";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please consider removing space before </a>.

}

String getEscapedUrl() {
return getEncoder().encodeForHTMLAttribute(getPrUrl().toASCIIString());
}

String getEscapedDescription() {
return getEncoder()
.encodeForHTML("PR #" + this.getPullRequestId() + " " + this.getPullRequestTitle());
}

URI getPrUrl() {
try {
return new URI(stashHost)
.resolve(
new URI(
null,
null,
"/projects/"
+ this.getDestinationRepositoryOwner()
+ "/repos/"
+ this.getDestinationRepositoryName()
+ "/pull-requests/"
+ this.getPullRequestId(),
null));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use String.format and drop this. (also in getEscapedDescription)

} catch (URISyntaxException e) {
throw new IllegalStateException(e);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sb-contrib detects an issue here: "Unconstrained method stashpullrequestbuilder.stashpullrequestbuilder.StashCause.getPrUrl() converts checked exception to unchecked [stashpullrequestbuilder.stashpullrequestbuilder.StashCause] At StashCause.java:[line 160] EXS_EXCEPTION_SOFTENING_NO_CONSTRAINTS"
Let's use checked exceptions, the compiler would force us to handle them.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hiding the exception was intentional: my rationale was that it's unlikely or impossible to happen given the arguments

}
}

private static Encoder getEncoder() {
return DefaultEncoder.getInstance();
}
}
1 change: 1 addition & 0 deletions src/main/resources/ESAPI.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ESAPI.Encoder=org.owasp.esapi.reference.DefaultEncoder
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The final newline is missing. It would be better to have it.

Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package stashpullrequestbuilder.stashpullrequestbuilder;

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.object.HasToString.hasToString;
import static org.junit.Assert.assertThat;

import org.junit.Test;

public class StashCauseTest {

@Test
public void short_description_doesnt_allow_injection() {

StashCause stashCause =
new StashCause(
"",
"",
"",
"",
"",
PULL_REQUEST_ID,
OWNER,
DESTINATION_REPOSITORY_NAME,
PULL_REQUEST_TITLE,
"",
"",
"",
"",
null);

assertThat(
stashCause.getShortDescription(),
is(
"<a href='&#x2f;projects&#x2f;owner&#x25;3C&#x25;3E&amp;&#x27;&#x25;22&#x2f;repos&#x2f;name&#x25;3C&#x25;3E&amp;&#x27;&#x25;22&#x2f;pull-requests&#x2f;id&#x25;3C&#x25;3E&amp;&#x27;&#x25;22'>"
+ "PR &#x23;id&lt;&gt;&amp;&#x27;&quot; title&lt;&gt;&amp;&#x27;&quot; </a>"));
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A shorter string would be more readable. We are testing that the escaping is done at all. It would be too much to test the underlying quoting algorithm.

}

@Test
public void will_produce_valid_PR_url() {

StashCause stashCause =
new StashCause(
"https://stash.host",
"",
"",
"",
"",
PULL_REQUEST_ID,
OWNER,
DESTINATION_REPOSITORY_NAME,
PULL_REQUEST_TITLE,
"",
"",
"",
"",
null);

assertThat(
stashCause.getPrUrl(),
hasToString(
"https://stash.host/projects/owner%3C%3E&'%22/repos/name%3C%3E&'%22/pull-requests/id%3C%3E&'%22"));
}

@Test
public void will_escape_PR_url() {

StashCause stashCause =
new StashCause(
"https://stash.host",
"",
"",
"",
"",
PULL_REQUEST_ID,
OWNER,
DESTINATION_REPOSITORY_NAME,
PULL_REQUEST_TITLE,
"",
"",
"",
"",
null);

assertThat(
stashCause.getEscapedUrl(),
is(
"https&#x3a;&#x2f;&#x2f;stash.host&#x2f;projects&#x2f;owner&#x25;3C&#x25;3E&amp;&#x27;&#x25;22&#x2f;repos&#x2f;name&#x25;3C&#x25;3E&amp;&#x27;&#x25;22&#x2f;pull-requests&#x2f;id&#x25;3C&#x25;3E&amp;&#x27;&#x25;22"));
}

@Test
public void will_escape_PR_description() {

StashCause stashCause =
new StashCause(
"https://stash.host",
"",
"",
"",
"",
PULL_REQUEST_ID,
OWNER,
DESTINATION_REPOSITORY_NAME,
PULL_REQUEST_TITLE,
"",
"",
"",
"",
null);

assertThat(
stashCause.getEscapedDescription(),
is("PR &#x23;id&lt;&gt;&amp;&#x27;&quot; title&lt;&gt;&amp;&#x27;&quot;"));
}

public static final String OWNER = "owner<>&'\"";
public static final String DESTINATION_REPOSITORY_NAME = "name<>&'\"";
public static final String PULL_REQUEST_ID = "id<>&'\"";
public static final String PULL_REQUEST_TITLE = "title<>&'\"";
}