Bug 1528562 support POST with 303 redirect in identity.launchWebAuthFlow r=rpl,Ehsan

nsBrowserStatusFilter is updated to not filter out STATE_IS_REDIRECTED_DOCUMENT.

The test here is adding a way to have a "login form" do a post to a server script, which then does a 303 redirect.  This mimics what some services, including LinkedIn do during this stage.

Differential Revision: https://phabricator.services.mozilla.com/D26969

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Shane Caraveo 2019-04-11 11:25:02 +00:00
parent e1abf1b768
commit e5dba8b292
4 changed files with 61 additions and 15 deletions

View File

@ -4,12 +4,23 @@
<script>
"use strict";
var url = new URL(location);
var end = new URL(url.searchParams.get("redirect_uri"));
end.searchParams.set("access_token", "here ya go");
location.href = end.href;
onload = () => {
let url = new URL(location);
if (url.searchParams.get("post")) {
let server_redirect = `${url.searchParams.get("server_uri")}?redirect_uri=${encodeURIComponent(url.searchParams.get("redirect_uri"))}`;
let form = document.forms.testform;
form.setAttribute("action", server_redirect);
form.submit();
} else {
let end = new URL(url.searchParams.get("redirect_uri"));
end.searchParams.set("access_token", "here ya go");
location.href = end.href;
}
};
</script>
</head>
<body>
<form name="testform" action="" method="POST">
</form>
</body>
</html>

View File

@ -9,7 +9,11 @@ function handleRequest(request, response) {
response.setStatusLine(request.httpVersion, 200, "OK");
response.write("ok");
} else {
response.setStatusLine(request.httpVersion, 302, "Moved Temporarily");
if (request.method == "POST") {
response.setStatusLine(request.httpVersion, 303, "Redirected");
} else {
response.setStatusLine(request.httpVersion, 302, "Moved Temporarily");
}
let url = new URL(params.get("redirect_uri") || params.get("default_redirect"));
url.searchParams.set("access_token", "here ya go");
response.setHeader("Location", url.href);

View File

@ -138,7 +138,7 @@ add_task(async function test_otherRedirectURL() {
await extension.unload();
});
function background_launchWebAuthFlow(interactive, path, redirect = true, useRedirectUri = true) {
function background_launchWebAuthFlow({interactive = false, path = "redirect_auto.sjs", params = {}, redirect = true, useRedirectUri = true} = {}) {
let uri_path = useRedirectUri ? "identity_cb" : "";
let expected_redirect = `https://35b64b676900f491c00e7f618d43f7040e88422e.example.com/${uri_path}`;
let base_uri = "https://example.com/tests/toolkit/components/extensions/test/mochitest/";
@ -146,16 +146,21 @@ function background_launchWebAuthFlow(interactive, path, redirect = true, useRed
browser.test.assertEq(expected_redirect, redirect_uri, "expected redirect uri matches hash");
let url = `${base_uri}${path}`;
if (useRedirectUri) {
url = `${url}?redirect_uri=${encodeURIComponent(redirect_uri)}`;
params.redirect_uri = redirect_uri;
} else {
// We kind of fake it with the redirect url that would normally be configured
// in the oauth service. This does still test that the identity service falls back
// to the extensions redirect url.
url = `${url}?default_redirect=${encodeURIComponent(expected_redirect)}`;
params.default_redirect = expected_redirect;
}
if (!redirect) {
url = `${url}&no_redirect=1`;
params.no_redirect = 1;
}
let query = [];
for (let [param, value] of Object.entries(params)) {
query.push(`${param}=${encodeURIComponent(value)}`);
}
url = `${url}?${query.join("&")}`;
// Ensure we do not start the actual request for the redirect url.
browser.webRequest.onBeforeRequest.addListener(details => {
@ -197,7 +202,7 @@ add_task(async function test_autoRedirect() {
"https://*.example.com/*",
],
},
background: `(${background_launchWebAuthFlow})(false, "redirect_auto.sjs")`,
background: `(${background_launchWebAuthFlow})()`,
});
await extension.startup();
@ -219,7 +224,7 @@ add_task(async function test_autoRedirect_noRedirectURI() {
"https://*.example.com/*",
],
},
background: `(${background_launchWebAuthFlow})(false, "redirect_auto.sjs", true, false)`,
background: `(${background_launchWebAuthFlow})({useRedirectUri: false})`,
});
await extension.startup();
@ -242,7 +247,7 @@ add_task(async function test_noRedirect() {
"https://*.example.com/*",
],
},
background: `(${background_launchWebAuthFlow})(false, "redirect_auto.sjs", false)`,
background: `(${background_launchWebAuthFlow})({redirect: false})`,
});
await extension.startup();
@ -268,13 +273,38 @@ add_task(async function test_interaction() {
"https://*.example.com/*",
],
},
background: `(${background_launchWebAuthFlow})(true, "oauth.html")`,
background: `(${background_launchWebAuthFlow})({interactive: true, path: "oauth.html"})`,
});
await extension.startup();
await extension.awaitMessage("done");
await extension.unload();
});
// Tests the situation where the oauth provider redirects with a 303.
add_task(async function test_auto303Redirect() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"applications": {
"gecko": {
"id": "identity@mozilla.org",
},
},
"permissions": [
"webRequest",
"identity",
"https://*.example.com/*",
],
},
background: `(${background_launchWebAuthFlow})({interactive: true, path: "oauth.html", params: {post: 303, server_uri: "redirect_auto.sjs"}})`,
});
await extension.startup();
await extension.awaitMessage("done");
await extension.unload();
});
</script>
</body>

View File

@ -161,8 +161,9 @@ nsBrowserStatusFilter::OnStateChange(nsIWebProgress *aWebProgress,
return NS_OK;
}
// Only notify listener for STATE_IS_NETWORK.
if (aStateFlags & STATE_IS_NETWORK) {
// Only notify listener for STATE_IS_NETWORK or STATE_IS_REDIRECTED_DOCUMENT
if (aStateFlags & STATE_IS_NETWORK ||
aStateFlags & STATE_IS_REDIRECTED_DOCUMENT) {
return mListener->OnStateChange(aWebProgress, aRequest, aStateFlags,
aStatus);
}