toolkit/components/extensions/test/mochitest/test_ext_identity.html
author Shane Caraveo <scaraveo@mozilla.com>
Fri, 28 Sep 2018 13:18:00 +0000
changeset 490159 3947b51293f6f3ddd8173b263cee69f7e4850a45
parent 468234 c10c705a1feae70c507bb644dcf2867cbe63db6f
child 523197 5d798451164267c5f4a4b69684361bc028d3d07a
child 527826 da3353f475f63ae929522fef23623c19871e48c1
permissions -rw-r--r--
Bug 1494328 fix launchWebAuthFlow to use default redirect_uri r=aswan a=pascalc 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

<!DOCTYPE HTML>
<html>
<head>
  <title>Test for WebExtension Identity</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <script src="/tests/SimpleTest/AddTask.js"></script>
  <script src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
  <script src="head.js"></script>
  <link rel="stylesheet" href="/tests/SimpleTest/test.css">
</head>
<body>

<script type="text/javascript">
"use strict";

add_task(async function setup() {
  await SpecialPowers.pushPrefEnv({
    set: [["extensions.webextensions.identity.redirectDomain", "example.com"]],
  });
});

add_task(async function test_noPermission() {
  let extension = ExtensionTestUtils.loadExtension({
    background() {
      browser.test.assertEq(undefined, browser.identity, "No identity api without permission");
      browser.test.sendMessage("done");
    },
  });

  await extension.startup();
  await extension.awaitMessage("done");
  await extension.unload();
});

add_task(async function test_badAuthURI() {
  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      "applications": {
        "gecko": {
          "id": "identity@mozilla.org",
        },
      },
      "permissions": [
        "identity",
        "https://example.com/",
      ],
    },
    async background() {
      let redirect_base = "https://35b64b676900f491c00e7f618d43f7040e88422e.example.com/";
      await browser.test.assertEq(redirect_base,
                                  browser.identity.getRedirectURL(),
                                  "redirect url ok");
      await browser.test.assertEq(redirect_base,
                                  browser.identity.getRedirectURL(""),
                                  "redirect url ok");
      await browser.test.assertEq(redirect_base + "foobar",
                                  browser.identity.getRedirectURL("foobar"),
                                  "redirect url ok");
      await browser.test.assertEq(redirect_base + "callback",
                                  browser.identity.getRedirectURL("/callback"),
                                  "redirect url ok");
      browser.test.sendMessage("done");
    },
  });

  await extension.startup();
  await extension.awaitMessage("done");
  await extension.unload();
});

add_task(async function test_badAuthURI() {
  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      "permissions": [
        "identity",
        "https://example.com/",
      ],
    },
    async background() {
      for (let url of ["foobar", "about:addons", "about:blank", "ftp://example.com/test"]) {
        await browser.test.assertThrows(
          () => { browser.identity.launchWebAuthFlow({interactive: true, url}); },
          /Type error for parameter details/,
          "details.url is invalid");
      }

      browser.test.sendMessage("done");
    },
  });

  await extension.startup();
  await extension.awaitMessage("done");
  await extension.unload();
});


add_task(async function test_badRequestURI() {
  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      "permissions": [
        "identity",
        "https://example.com/",
      ],
    },
    async background() {
      let base_uri = "https://example.com/tests/toolkit/components/extensions/test/mochitest/";
      let url = `${base_uri}?redirect_uri=badrobot}`;
      await browser.test.assertRejects(browser.identity.launchWebAuthFlow({interactive: true, url}),
                                       "redirect_uri is invalid", "invalid redirect url");
      browser.test.sendMessage("done");
    },
  });

  await extension.startup();
  await extension.awaitMessage("done");
  await extension.unload();
});

add_task(async function test_otherRedirectURL() {
  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      "permissions": [
        "identity",
        "https://example.com/",
      ],
    },
    async background() {
      let base_uri = "https://example.com/tests/toolkit/components/extensions/test/mochitest/";
      let url = `${base_uri}?redirect_uri=https://somesite.com/redirect`;
      await browser.test.assertRejects(browser.identity.launchWebAuthFlow({interactive: false, url}),
                                       "Requires user interaction", "alternate redirect_uri ok");
      browser.test.sendMessage("done");
    },
  });

  await extension.startup();
  await extension.awaitMessage("done");
  await extension.unload();
});

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(useRedirectUri ? uri_path : undefined);
  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)}`;
  } 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`;
  }

  // Ensure we do not start the actual request for the redirect url.
  browser.webRequest.onBeforeRequest.addListener(details => {
    if (details.url.startsWith(expected_redirect)) {
      browser.test.fail("onBeforeRequest called for redirect url");
    }
  }, {urls: ["https://35b64b676900f491c00e7f618d43f7040e88422e.example.com/*"]});

  browser.identity.launchWebAuthFlow({interactive, url}).then((redirectURL) => {
    browser.test.assertTrue(redirectURL.startsWith(redirect_uri), `correct redirect url ${redirectURL}`);
    if (redirect) {
      let url = new URL(redirectURL);
      browser.test.assertEq("here ya go", url.searchParams.get("access_token"), "Handled auto redirection");
    }
    browser.test.sendMessage("done");
  }).catch((error) => {
    if (redirect) {
      browser.test.fail(error.message);
    } else {
      browser.test.assertEq("Requires user interaction", error.message, "Auth page loaded, interaction required.");
    }
    browser.test.sendMessage("done");
  });
}

// Tests the situation where the oauth provider has already granted access and
// simply redirects the oauth client to provide the access key or code.
add_task(async function test_autoRedirect() {
  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      "applications": {
        "gecko": {
          "id": "identity@mozilla.org",
        },
      },
      "permissions": [
        "webRequest",
        "identity",
        "https://*.example.com/*",
      ],
    },
    background: `(${background_launchWebAuthFlow})(false, "redirect_auto.sjs")`,
  });

  await extension.startup();
  await extension.awaitMessage("done");
  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({
    manifest: {
      "applications": {
        "gecko": {
          "id": "identity@mozilla.org",
        },
      },
      "permissions": [
        "webRequest",
        "identity",
        "https://*.example.com/*",
      ],
    },
    background: `(${background_launchWebAuthFlow})(false, "redirect_auto.sjs", false)`,
  });

  await extension.startup();
  await extension.awaitMessage("done");
  await extension.unload();
});

// Tests the situation where the oauth provider must show a window where
// presumably the user interacts, then the redirect occurs and access key or
// code is provided.  We bypass any real interaction, but want the window to
// open and result in a redirect.
add_task(async function test_interaction() {
  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      "applications": {
        "gecko": {
          "id": "identity@mozilla.org",
        },
      },
      "permissions": [
        "webRequest",
        "identity",
        "https://*.example.com/*",
      ],
    },
    background: `(${background_launchWebAuthFlow})(true, "oauth.html")`,
  });

  await extension.startup();
  await extension.awaitMessage("done");
  await extension.unload();
});
</script>

</body>
</html>