diff --git a/pom.xml b/pom.xml index 230865e0cd..cdb5f4ef7b 100644 --- a/pom.xml +++ b/pom.xml @@ -1430,6 +1430,9 @@ Vladimir Babin vovababin@gmail.com + + Vidya m + diff --git a/src/main/java/org/htmlunit/WebClient.java b/src/main/java/org/htmlunit/WebClient.java index 29a8be9e7e..87b8032fe8 100644 --- a/src/main/java/org/htmlunit/WebClient.java +++ b/src/main/java/org/htmlunit/WebClient.java @@ -153,6 +153,7 @@ * @author René Schwietzke * @author Sven Strickroth * @author Ashutosh Panda + * @author Vidya m */ @SuppressWarnings("PMD.TooManyFields") public class WebClient implements Serializable, AutoCloseable { @@ -1711,6 +1712,8 @@ && getOptions().isRedirectEnabled() + webResponse.getWebRequest().getUrl(), webResponse); } + final boolean crossOriginRedirect = !UrlUtils.isSameOrigin(url, newUrl); + if (status == HttpStatus.MOVED_PERMANENTLY_301 || status == HttpStatus.FOUND_302 || status == HttpStatus.SEE_OTHER_303) { @@ -1723,6 +1726,10 @@ && getOptions().isRedirectEnabled() for (final Map.Entry entry : webRequest.getAdditionalHeaders().entrySet()) { wrs.setAdditionalHeader(entry.getKey(), entry.getValue()); } + if (crossOriginRedirect) { + // credentials are not forwarded to another origin + wrs.removeAdditionalHeader("Authorization"); + } wrs.setFetchDestination(webRequest.getFetchDestination()); wrs.setFetchModeOverride(webRequest.getFetchModeOverride()); wrs.setRequestingUrl(webRequest.getRequestingUrl()); @@ -1751,6 +1758,10 @@ else if (status == HttpStatus.TEMPORARY_REDIRECT_307 for (final Map.Entry entry : webRequest.getAdditionalHeaders().entrySet()) { wrs.setAdditionalHeader(entry.getKey(), entry.getValue()); } + if (crossOriginRedirect) { + // credentials are not forwarded to another origin + wrs.removeAdditionalHeader("Authorization"); + } return loadWebResponseFromWebConnection(wrs, allowedRedirects - 1); } diff --git a/src/main/java/org/htmlunit/html/HtmlPage.java b/src/main/java/org/htmlunit/html/HtmlPage.java index eb10ac6724..5a0cbe7bf7 100644 --- a/src/main/java/org/htmlunit/html/HtmlPage.java +++ b/src/main/java/org/htmlunit/html/HtmlPage.java @@ -143,6 +143,7 @@ * @author Ronny Shapiro * @author Lai Quang Duong * @author Sven Strickroth + * @author Vidya m */ @SuppressWarnings("PMD.TooManyFields") public class HtmlPage extends SgmlPage { @@ -1105,6 +1106,10 @@ private Object loadJavaScriptFromUrl(final URL url, final Charset scriptCharset, final WebRequest request = new WebRequest(url); // copy all headers from the referring request request.setAdditionalHeaders(new HashMap<>(referringRequest.getAdditionalHeaders())); + if (!UrlUtils.isSameOrigin(referringRequest.getUrl(), url)) { + // credentials are not forwarded to another origin + request.removeAdditionalHeader("Authorization"); + } // at least overwrite this headers request.setAdditionalHeader(HttpHeader.ACCEPT, client.getBrowserVersion().getScriptAcceptHeader()); diff --git a/src/test/java/org/htmlunit/WebClientTest.java b/src/test/java/org/htmlunit/WebClientTest.java index 92ae189b2f..a34c483c75 100644 --- a/src/test/java/org/htmlunit/WebClientTest.java +++ b/src/test/java/org/htmlunit/WebClientTest.java @@ -74,6 +74,7 @@ * @author Ronald Brill * @author Carsten Steul * @author Joerg Werner + * @author Vidya m */ public class WebClientTest extends SimpleWebTestCase { @@ -526,6 +527,39 @@ private void redirection_AdditionalHeadersMaintained(final int statusCode) throw assertEquals("bar", conn.getLastAdditionalHeaders().get("foo")); } + /** + * Verifies that the "Authorization" header of the original {@link WebRequest} is only + * sent to the redirect location if the redirect does not leave the origin. + * @throws Exception if an error occurs + */ + @Test + public void redirection_AuthorizationHeaderDroppedForCrossOrigin() throws Exception { + for (final int statusCode : new int[] {301, 302, 303, 307, 308}) { + redirection_AuthorizationHeader(statusCode, URL_SECOND, "Bearer secret"); + redirection_AuthorizationHeader(statusCode, URL_THIRD, null); + } + } + + private void redirection_AuthorizationHeader(final int statusCode, final URL redirectUrl, + final String expectedAuthorization) throws Exception { + final WebClient client = getWebClient(); + final MockWebConnection conn = new MockWebConnection(); + client.setWebConnection(conn); + + final List headers = asList(new NameValuePair("Location", redirectUrl.toString())); + conn.setResponse(URL_FIRST, "", statusCode, "", MimeType.TEXT_HTML, headers); + conn.setResponse(redirectUrl, DOCTYPE_HTML + "abc"); + + final WebRequest request = new WebRequest(URL_FIRST); + request.setAdditionalHeader("Authorization", "Bearer secret"); + request.setAdditionalHeader("foo", "bar"); + client.getPage(request); + + assertEquals(redirectUrl, conn.getLastWebRequest().getUrl()); + assertEquals(expectedAuthorization, conn.getLastAdditionalHeaders().get("Authorization")); + assertEquals("bar", conn.getLastAdditionalHeaders().get("foo")); + } + /** * Basic logic for all the redirection tests. * diff --git a/src/test/java/org/htmlunit/html/HtmlScriptTest.java b/src/test/java/org/htmlunit/html/HtmlScriptTest.java index 729106bcaa..cf5bb989d2 100644 --- a/src/test/java/org/htmlunit/html/HtmlScriptTest.java +++ b/src/test/java/org/htmlunit/html/HtmlScriptTest.java @@ -25,6 +25,7 @@ import org.htmlunit.MockWebConnection; import org.htmlunit.SimpleWebTestCase; import org.htmlunit.WebClient; +import org.htmlunit.WebRequest; import org.htmlunit.junit.annotation.Alerts; import org.htmlunit.util.MimeType; import org.junit.jupiter.api.Test; @@ -37,6 +38,7 @@ * @author Ahmed Ashour * @author Ronald Brill * @author Ronny Shapiro + * @author Vidya m */ public class HtmlScriptTest extends SimpleWebTestCase { @@ -83,6 +85,41 @@ public void badExternalScriptReference() throws Exception { } } + /** + * Verifies that the "Authorization" header of the page request is only sent + * with the request for an external script if the script has the same origin. + * @throws Exception if an error occurs + */ + @Test + public void authorizationHeaderNotSentToCrossOriginScript() throws Exception { + externalScriptAuthorizationHeader(new URL(URL_FIRST, "script.js"), "Bearer secret"); + externalScriptAuthorizationHeader(new URL(URL_THIRD, "script.js"), null); + } + + private void externalScriptAuthorizationHeader(final URL scriptUrl, + final String expectedAuthorization) throws Exception { + final String html = DOCTYPE_HTML + + "foo\n" + + "\n" + + ""; + + final WebClient client = getWebClient(); + + final MockWebConnection webConnection = new MockWebConnection(); + webConnection.setResponse(URL_FIRST, html); + webConnection.setResponse(scriptUrl, "var i = 7;", MimeType.TEXT_JAVASCRIPT); + client.setWebConnection(webConnection); + + final WebRequest request = new WebRequest(URL_FIRST); + request.setAdditionalHeader("Authorization", "Bearer secret"); + request.setAdditionalHeader("foo", "bar"); + client.getPage(request); + + assertEquals(scriptUrl, webConnection.getLastWebRequest().getUrl()); + assertEquals(expectedAuthorization, webConnection.getLastAdditionalHeaders().get("Authorization")); + assertEquals("bar", webConnection.getLastAdditionalHeaders().get("foo")); + } + /** * @throws Exception if an error occurs */