Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions src/main/java/com/twilio/security/RequestValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,14 +136,25 @@ private String addPort(String url) {

private String updatePort(URI url, int newPort) {
try {
return new URI(
url.getScheme(),
url.getUserInfo(),
url.getHost(),
newPort,
url.getPath(),
url.getQuery(),
url.getFragment()).toString();
StringBuilder sb = new StringBuilder();
sb.append(url.getScheme()).append("://");
if (url.getRawUserInfo() != null) {
sb.append(url.getRawUserInfo()).append("@");
}
sb.append(url.getHost());
if (newPort != -1) {
sb.append(":").append(newPort);
}
if (url.getRawPath() != null) {
sb.append(url.getRawPath());
}
if (url.getRawQuery() != null) {
sb.append("?").append(url.getRawQuery());
}
if (url.getRawFragment() != null) {
sb.append("#").append(url.getRawFragment());
}
return sb.toString();
} catch (Exception e) {
return url.toString();
}
Expand Down
26 changes: 26 additions & 0 deletions src/test/java/com/twilio/security/RequestValidatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,30 @@ public void testValidateAddsPortHttp() {
Assert.assertTrue("Validator did not add port 80 to http url", isValid);
}

@Test
public void testValidatePreservesUrlEncodingInQuery() {
// Test case for the specific issue: URLs with encoded characters in query string
String urlWithoutPort = "https://someurl.com/somepath?param1=client%3AAnonymous";
String urlWithPort = "https://someurl.com:443/somepath?param1=client%3AAnonymous";
RequestValidator validator = new RequestValidator("1234567890");

// Generate a signature for the URL without port
Map<String, String> emptyParams = new HashMap<>();
String signature = null;
try {
java.lang.reflect.Method method = RequestValidator.class.getDeclaredMethod("getValidationSignature", String.class, java.util.Map.class);
method.setAccessible(true);
signature = (String) method.invoke(validator, urlWithoutPort, emptyParams);
} catch (Exception e) {
Assert.fail("Could not generate signature: " + e.getMessage());
}

// Both URLs should validate with the same signature since they should be treated as equivalent
boolean validWithoutPort = validator.validate(urlWithoutPort, emptyParams, signature);
boolean validWithPort = validator.validate(urlWithPort, emptyParams, signature);

Assert.assertTrue("URL without port should validate", validWithoutPort);
Assert.assertTrue("URL with port should validate (encoding preserved)", validWithPort);
}

}
Loading