Bug 1494328 fix launchWebAuthFlow to use default redirect_uri r=aswan

Some oauth services require the redirect uri be configured on their service,
and the reject the redirect_uri param if we send it.  Chrome works fine in this scenario,
but we have been requiring the redirect_uri be provided.  This addresses that requirement
by using our own default redirect url, which would be the url used to configure the
oauth service.

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

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Shane Caraveo 2018-09-28 13:18:00 +00:00
parent b44224fb5f
commit e7fedf66f4
4 changed files with 54 additions and 23 deletions

View File

@ -31,6 +31,22 @@ this.identity = class extends ExtensionAPI {
url.pathname = path;
return url.href;
},
launchWebAuthFlow: function(details) {
// Validate the url and retreive redirect_uri if it was provided.
let url, redirectURI;
try {
url = new URL(details.url);
} catch (e) {
return Promise.reject({message: "details.url is invalid"});
}
try {
redirectURI = new URL(url.searchParams.get("redirect_uri") || this.getRedirectURL());
} catch (e) {
return Promise.reject({message: "redirect_uri is invalid"});
}
return context.childManager.callParentAsyncFunction("identity.launchWebAuthFlowInParent", [details, redirectURI.href]);
},
},
};
}

View File

@ -5,7 +5,7 @@
ChromeUtils.defineModuleGetter(this, "Services",
"resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyGlobalGetters(this, ["URL", "XMLHttpRequest"]);
XPCOMUtils.defineLazyGlobalGetters(this, ["XMLHttpRequest"]);
var {
promiseDocumentLoaded,
@ -94,23 +94,7 @@ this.identity = class extends ExtensionAPI {
getAPI(context) {
return {
identity: {
launchWebAuthFlow: function(details) {
// In OAuth2 the url should have a redirect_uri param, parse the url and grab it
let url, redirectURI;
try {
url = new URL(details.url);
} catch (e) {
return Promise.reject({message: "details.url is invalid"});
}
try {
redirectURI = new URL(url.searchParams.get("redirect_uri"));
if (!redirectURI) {
return Promise.reject({message: "redirect_uri is missing"});
}
} catch (e) {
return Promise.reject({message: "redirect_uri is invalid"});
}
launchWebAuthFlowInParent: function(details, redirectURI) {
// If the request is automatically redirected the user has already
// authorized and we do not want to show the window.
return checkRedirected(details.url, redirectURI).catch((requestError) => {

View File

@ -10,7 +10,7 @@ function handleRequest(request, response) {
response.write("ok");
} else {
response.setStatusLine(request.httpVersion, 302, "Moved Temporarily");
let url = new URL(params.get("redirect_uri"));
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,12 +138,21 @@ add_task(async function test_otherRedirectURL() {
await extension.unload();
});
function background_launchWebAuthFlow(interactive, path, redirect = true) {
let expected_redirect = "https://35b64b676900f491c00e7f618d43f7040e88422e.example.com/identity_cb";
function background_launchWebAuthFlow(interactive, path, 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/";
let redirect_uri = browser.identity.getRedirectURL("/identity_cb");
let redirect_uri = browser.identity.getRedirectURL(useRedirectUri ? uri_path : undefined);
browser.test.assertEq(expected_redirect, redirect_uri, "expected redirect uri matches hash");
let url = `${base_uri}${path}?redirect_uri=${encodeURIComponent(redirect_uri)}`;
let url = `${base_uri}${path}`;
if (useRedirectUri) {
url = `${url}?redirect_uri=${encodeURIComponent(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)}`;
}
if (!redirect) {
url = `${url}&no_redirect=1`;
}
@ -196,6 +205,28 @@ add_task(async function test_autoRedirect() {
await extension.unload();
});
add_task(async function test_autoRedirect_noRedirectURI() {
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"applications": {
"gecko": {
"id": "identity@mozilla.org",
},
},
"permissions": [
"webRequest",
"identity",
"https://*.example.com/*",
],
},
background: `(${background_launchWebAuthFlow})(false, "redirect_auto.sjs", true, false)`,
});
await extension.startup();
await extension.awaitMessage("done");
await extension.unload();
});
// Tests the situation where the oauth provider has not granted access and interactive=false
add_task(async function test_noRedirect() {
let extension = ExtensionTestUtils.loadExtension({