Skip to content

Commit

Permalink
Bug 1483631 - Prompt with both first party and third party origin if …
Browse files Browse the repository at this point in the history
…we are delegating permission with allows all feature policy. r=baku

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

--HG--
extra : moz-landing-system : lando
  • Loading branch information
Thomas Nguyen committed Dec 4, 2019
1 parent a0b817a commit 1e82cdc
Show file tree
Hide file tree
Showing 28 changed files with 517 additions and 112 deletions.
4 changes: 2 additions & 2 deletions browser/base/content/test/permissions/browser.ini
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
support-files=
head.js
permissions.html

temporary_permissions_subframe.html
temporary_permissions_frame.html
[browser_canvas_fingerprinting_resistance.js]
skip-if = debug || os == "linux" && asan # Bug 1522069
[browser_permissions.js]
Expand All @@ -21,7 +22,6 @@ support-files=
[browser_reservedkey.js]
[browser_temporary_permissions.js]
support-files =
temporary_permissions_subframe.html
../webrtc/get_user_media.html
[browser_autoplay_blocked.js]
support-files =
Expand Down
226 changes: 164 additions & 62 deletions browser/base/content/test/permissions/browser_permission_delegate_geo.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ const CROSS_SUBFRAME_PAGE =
getRootDirectory(gTestPath).replace("chrome://mochitests/content", ORIGIN) +
"temporary_permissions_subframe.html";

const CROSS_FRAME_PAGE =
getRootDirectory(gTestPath).replace("chrome://mochitests/content", ORIGIN) +
"temporary_permissions_frame.html";

const PromptResult = {
ALLOW: "allow",
DENY: "deny",
Expand All @@ -18,6 +22,93 @@ var Perms = Services.perms;
var uri = NetUtil.newURI(ORIGIN);
var principal = Services.scriptSecurityManager.createContentPrincipal(uri, {});

async function checkNotificationBothOrigins(
firstPartyOrigin,
thirdPartyOrigin
) {
// Notification is shown, check label and deny to clean
let popuphidden = BrowserTestUtils.waitForEvent(
PopupNotifications.panel,
"popuphidden"
);

let notification = PopupNotifications.panel.firstElementChild;
// Check the label of the notificaiton should be the first party
is(
PopupNotifications.getNotification("geolocation").options.name,
firstPartyOrigin,
"Use first party's origin"
);

// Check the second name of the notificaiton should be the third party
is(
PopupNotifications.getNotification("geolocation").options.secondName,
thirdPartyOrigin,
"Use third party's origin"
);

// Check remember checkbox is hidden
let checkbox = notification.checkbox;
ok(!!checkbox, "checkbox is present");
ok(checkbox.hidden, "checkbox is not visible");
ok(!checkbox.checked, "checkbox not checked");

EventUtils.synthesizeMouseAtCenter(notification.secondaryButton, {});
await popuphidden;
}

async function checkGeolocation(browser, frameId, expect) {
let waitForPrompt = BrowserTestUtils.waitForEvent(
PopupNotifications.panel,
"popupshown"
);

let isPrompt = expect == PromptResult.PROMPT;
await SpecialPowers.spawn(
browser,
[{ frameId, expect, isPrompt }],
async args => {
let frame = content.document.getElementById(args.frameId);

let waitForNoPrompt = new Promise(resolve => {
function onMessage(event) {
// Check the result right here because there's no notification
Assert.equal(
event.data,
args.expect,
"Correct expectation for third party"
);
content.window.removeEventListener("message", onMessage);
resolve();
}

if (!args.isPrompt) {
content.window.addEventListener("message", onMessage);
}
});

await content.SpecialPowers.spawn(frame, [], async () => {
const { E10SUtils } = ChromeUtils.import(
"resource://gre/modules/E10SUtils.jsm"
);

E10SUtils.wrapHandlingUserInput(this.content, true, function() {
let frameDoc = this.content.document;
frameDoc.getElementById("geo").click();
});
});

if (!args.isPrompt) {
await waitForNoPrompt;
}
}
);

if (isPrompt) {
await waitForPrompt;
}
}

add_task(async function setup() {
await new Promise(r => {
SpecialPowers.pushPrefEnv(
Expand Down Expand Up @@ -48,28 +139,7 @@ add_task(async function testUseTempPermissionsFirstParty() {
browser
);

// Request a permission.
await ContentTask.spawn(browser, uri.host, async function(host0) {
let frame = content.document.getElementById("frame");
function onMessage(event) {
// Check the result right here because there's no notification
is(event.data, "deny", "Expected deny for third party");
content.window.removeEventListener("message", onMessage);
}

content.window.addEventListener("message", onMessage);

await content.SpecialPowers.spawn(frame, [host0], async function(host) {
const { E10SUtils } = ChromeUtils.import(
"resource://gre/modules/E10SUtils.jsm"
);

E10SUtils.wrapHandlingUserInput(this.content, true, function() {
let frameDoc = this.content.document;
frameDoc.getElementById("geo").click();
});
});
});
await checkGeolocation(browser, "frame", PromptResult.DENY);

SitePermissions.removeFromPrincipal(principal, "geo", browser);
});
Expand All @@ -83,48 +153,9 @@ add_task(async function testUsePersistentPermissionsFirstParty() {
) {
async function checkPermission(aPermission, aExpect) {
PermissionTestUtils.add(uri, "geo", aPermission);

let waitForPrompt = BrowserTestUtils.waitForEvent(
PopupNotifications.panel,
"popupshown"
);

// Request a permission.
await ContentTask.spawn(
browser,
{ host: uri.host, expect: aExpect },
async function(args) {
let frame = content.document.getElementById("frame");
if (args.expect != "prompt") {
function onMessage(event) {
// Check the result right here because there's no notification
is(
event.data,
args.expect,
"Expected correct permission for third party"
);
content.window.removeEventListener("message", onMessage);
}
content.window.addEventListener("message", onMessage);
}

await content.SpecialPowers.spawn(frame, [args.host], async function(
host
) {
const { E10SUtils } = ChromeUtils.import(
"resource://gre/modules/E10SUtils.jsm"
);

E10SUtils.wrapHandlingUserInput(this.content, true, function() {
let frameDoc = this.content.document;
frameDoc.getElementById("geo").click();
});
});
}
);
await checkGeolocation(browser, "frame", aExpect);

if (aExpect == PromptResult.PROMPT) {
await waitForPrompt;
// Notification is shown, check label and deny to clean
let popuphidden = BrowserTestUtils.waitForEvent(
PopupNotifications.panel,
Expand Down Expand Up @@ -153,3 +184,74 @@ add_task(async function testUsePersistentPermissionsFirstParty() {
await checkPermission(Perms.ALLOW_ACTION, PromptResult.ALLOW);
});
});

// Test that we should prompt if we are in unsafe permission delegation. The
// prompt popup should include both first and third party origin.
add_task(async function testPromptInMaybeUnsafePermissionDelegation() {
await BrowserTestUtils.withNewTab(CROSS_SUBFRAME_PAGE, async function(
browser
) {
// Persistent allow top level origin
PermissionTestUtils.add(uri, "geo", Perms.ALLOW_ACTION);

await checkGeolocation(browser, "frameAllowsAll", PromptResult.PROMPT);
await checkNotificationBothOrigins(uri.host, "example.org");

SitePermissions.removeFromPrincipal(null, "geo", browser);
PermissionTestUtils.remove(uri, "geo");
});
});

// Test that we should prompt if we are in unsafe permission delegation and
// change location to origin which is not explicitly trusted. The prompt popup
// should include both first and third party origin.
add_task(async function testPromptChangeLocatioUnsafePermissionDelegation() {
await BrowserTestUtils.withNewTab(CROSS_SUBFRAME_PAGE, async function(
browser
) {
// Persistent allow top level origin
PermissionTestUtils.add(uri, "geo", Perms.ALLOW_ACTION);

// Request change location.
await ContentTask.spawn(browser, { host: uri.host }, async function(args) {
let frame = content.document.getElementById("frameAllowsAll");
await new Promise(resolve => {
function listener() {
frame.removeEventListener("load", listener, true);
resolve();
}
frame.addEventListener("load", listener, true);

frame.contentWindow.location =
"https://test1.example.com/browser/browser/base/content/test/permissions/permissions.html";
});
});

await checkGeolocation(browser, "frameAllowsAll", PromptResult.PROMPT);
await checkNotificationBothOrigins(uri.host, "test1.example.com");

SitePermissions.removeFromPrincipal(null, "geo", browser);
PermissionTestUtils.remove(uri, "geo");
});
});

// If we are in unsafe permission delegation and the origin is explicitly
// trusted in ancestor chain. Do not need prompt
add_task(async function testExplicitlyAllowedInChain() {
await BrowserTestUtils.withNewTab(CROSS_FRAME_PAGE, async function(browser) {
// Persistent allow top level origin
PermissionTestUtils.add(uri, "geo", Perms.ALLOW_ACTION);

const iframeAncestor = await SpecialPowers.spawn(browser, [], () => {
return content.document.getElementById("frameAncestor").browsingContext;
});

await checkGeolocation(
iframeAncestor,
"frameAllowsAll",
PromptResult.ALLOW
);

PermissionTestUtils.remove(uri, "geo");
});
});
5 changes: 3 additions & 2 deletions browser/base/content/test/permissions/permissions.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
function requestGeo() {
return navigator.geolocation.getCurrentPosition(() => {
parent.postMessage("allow", "*");
}, () => {
parent.postMessage("deny", "*");
}, error => {
// PERMISSION_DENIED = 1
parent.postMessage(error.code == 1 ? "deny" : "allow", "*");
});
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Permissions Subframe Test</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
</head>
<body>
<iframe id="frameAncestor"
src="https://test1.example.com/browser/browser/base/content/test/permissions/temporary_permissions_subframe.html"
allow="geolocation 'src' https://example.org"></iframe>
</body>
</html>
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"></meta>
</head>
<body>
<iframe id="frame" src="https://example.org/browser/browser/base/content/test/permissions/permissions.html" allow="geolocation"/>
<iframe id="frame" src="https://example.org/browser/browser/base/content/test/permissions/permissions.html" allow="geolocation"></iframe>
<iframe id="frameAllowsAll" src="https://example.org/browser/browser/base/content/test/permissions/permissions.html" allow="geolocation *"></iframe>
</body>
</html>
3 changes: 3 additions & 0 deletions browser/locales/en-US/chrome/browser/browser.properties
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,9 @@ geolocation.dontAllowLocation=Don’t Allow
geolocation.dontAllowLocation.accesskey=n
geolocation.shareWithSite3=Will you allow %S to access your location?
geolocation.shareWithFile3=Will you allow this local file to access your location?
# LOCALIZATION NOTE(geolocation.shareWithSiteUnsafeDelegation):
# %1$S is the first party origin, %2$S is the third party origin.
geolocation.shareWithSiteUnsafeDelegation=Will you allow %1$S to give %2$S permission to access your location?
geolocation.remember=Remember this decision

# Persistent storage UI
Expand Down
Loading

0 comments on commit 1e82cdc

Please sign in to comment.