Bug 1028398 - FxA will silently provide user's email to privileged apps in 2.0. Part 1: Add moz-firefox-accounts permission. r=jedp, fabrice

This commit is contained in:
Fernando Jiménez 2014-07-11 16:13:32 +02:00
parent 90365227a0
commit 4c2613d1f3
3 changed files with 110 additions and 34 deletions

View File

@ -367,6 +367,17 @@ this.PermissionsTable = { geolocation: {
privileged: PROMPT_ACTION,
certified: ALLOW_ACTION,
access: ["read", "write", "create"]
},
"firefox-accounts": {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
"moz-firefox-accounts": {
app: DENY_ACTION,
privileged: PROMPT_ACTION,
certified: ALLOW_ACTION,
substitute: ["firefox-accounts"]
}
};

View File

@ -10,6 +10,7 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const PREF_FXA_ENABLED = "identity.fxaccounts.enabled";
const FXA_PERMISSION = "firefox-accounts";
// This is the parent process corresponding to nsDOMIdentity.
this.EXPORTED_SYMBOLS = ["DOMIdentity"];
@ -38,6 +39,10 @@ XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageListenerManager");
XPCOMUtils.defineLazyServiceGetter(this, "permissionManager",
"@mozilla.org/permissionmanager;1",
"nsIPermissionManager");
function log(...aMessageArgs) {
Logger.log.apply(Logger, ["DOMIdentity"].concat(aMessageArgs));
}
@ -234,6 +239,28 @@ this.DOMIdentity = {
this._mmContexts.delete(targetMM);
},
hasPermission: function(aMessage) {
// We only check that the firefox accounts permission is present in the
// manifest.
if (aMessage.json && aMessage.json.wantIssuer == "firefox-accounts") {
if (!aMessage.principal) {
return false;
}
let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
.getService(Ci.nsIScriptSecurityManager);
let uri = Services.io.newURI(aMessage.principal.origin, null, null);
let principal = secMan.getAppCodebasePrincipal(uri,
aMessage.principal.appId, aMessage.principal.isInBrowserElement);
let permission =
permissionManager.testPermissionFromPrincipal(principal,
FXA_PERMISSION);
return permission != Ci.nsIPermissionManager.UNKNOWN_ACTION &&
permission != Ci.nsIPermissionManager.DENY_ACTION;
}
return true;
},
// nsIMessageListener
receiveMessage: function DOMIdentity_receiveMessage(aMessage) {
let msg = aMessage.json;
@ -242,6 +269,10 @@ this.DOMIdentity = {
// used to send replies back to the proper window.
let targetMM = aMessage.target;
if (!this.hasPermission(aMessage)) {
throw new Error("PERMISSION_DENIED");
}
switch (aMessage.name) {
// RP
case "Identity:RP:Watch":

View File

@ -40,8 +40,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
const ERRORS = {
"ERROR_NOT_AUTHORIZED_FOR_FIREFOX_ACCOUNTS":
"Only privileged and certified apps may use Firefox Accounts",
"ERROR_INVALID_ASSERTION_AUDIENCE":
"Assertion audience may not differ from origin",
"ERROR_REQUEST_WHILE_NOT_HANDLING_USER_INPUT":
@ -150,7 +148,12 @@ nsDOMIdentity.prototype = {
// broken client to be able to call watch() any more. It's broken.
return;
}
this._identityInternal._mm.sendAsyncMessage("Identity:RP:Watch", message);
this._identityInternal._mm.sendAsyncMessage(
"Identity:RP:Watch",
message,
null,
this._window.document.nodePrincipal
);
},
request: function nsDOMIdentity_request(aOptions = {}) {
@ -221,7 +224,12 @@ nsDOMIdentity.prototype = {
}
this._rpCalls++;
this._identityInternal._mm.sendAsyncMessage("Identity:RP:Request", message);
this._identityInternal._mm.sendAsyncMessage(
"Identity:RP:Request",
message,
null,
this._window.document.nodePrincipal
);
},
logout: function nsDOMIdentity_logout() {
@ -241,7 +249,12 @@ nsDOMIdentity.prototype = {
return;
}
this._identityInternal._mm.sendAsyncMessage("Identity:RP:Logout", message);
this._identityInternal._mm.sendAsyncMessage(
"Identity:RP:Logout",
message,
null,
this._window.document.nodePrincipal
);
},
/*
@ -324,8 +337,12 @@ nsDOMIdentity.prototype = {
}
this._beginProvisioningCallback = aCallback;
this._identityInternal._mm.sendAsyncMessage("Identity:IDP:BeginProvisioning",
this.DOMIdentityMessage());
this._identityInternal._mm.sendAsyncMessage(
"Identity:IDP:BeginProvisioning",
this.DOMIdentityMessage(),
null,
this._window.document.nodePrincipal
);
},
genKeyPair: function nsDOMIdentity_genKeyPair(aCallback) {
@ -341,8 +358,12 @@ nsDOMIdentity.prototype = {
}
this._genKeyPairCallback = aCallback;
this._identityInternal._mm.sendAsyncMessage("Identity:IDP:GenKeyPair",
this.DOMIdentityMessage());
this._identityInternal._mm.sendAsyncMessage(
"Identity:IDP:GenKeyPair",
this.DOMIdentityMessage(),
null,
this._window.document.nodePrincipal
);
},
registerCertificate: function nsDOMIdentity_registerCertificate(aCertificate) {
@ -357,7 +378,12 @@ nsDOMIdentity.prototype = {
let message = this.DOMIdentityMessage();
message.cert = aCertificate;
this._identityInternal._mm.sendAsyncMessage("Identity:IDP:RegisterCertificate", message);
this._identityInternal._mm.sendAsyncMessage(
"Identity:IDP:RegisterCertificate",
message,
null,
this._window.document.nodePrincipal
);
},
raiseProvisioningFailure: function nsDOMIdentity_raiseProvisioningFailure(aReason) {
@ -372,7 +398,12 @@ nsDOMIdentity.prototype = {
let message = this.DOMIdentityMessage();
message.reason = aReason;
this._identityInternal._mm.sendAsyncMessage("Identity:IDP:ProvisioningFailure", message);
this._identityInternal._mm.sendAsyncMessage(
"Identity:IDP:ProvisioningFailure",
message,
null,
this._window.document.nodePrincipal
);
},
/**
@ -392,8 +423,12 @@ nsDOMIdentity.prototype = {
}
this._beginAuthenticationCallback = aCallback;
this._identityInternal._mm.sendAsyncMessage("Identity:IDP:BeginAuthentication",
this.DOMIdentityMessage());
this._identityInternal._mm.sendAsyncMessage(
"Identity:IDP:BeginAuthentication",
this.DOMIdentityMessage(),
null,
this._window.document.nodePrincipal
);
},
completeAuthentication: function nsDOMIdentity_completeAuthentication() {
@ -405,8 +440,12 @@ nsDOMIdentity.prototype = {
}
this._authenticationEnded = true;
this._identityInternal._mm.sendAsyncMessage("Identity:IDP:CompleteAuthentication",
this.DOMIdentityMessage());
this._identityInternal._mm.sendAsyncMessage(
"Identity:IDP:CompleteAuthentication",
this.DOMIdentityMessage(),
null,
this._window.document.nodePrincipal
);
},
raiseAuthenticationFailure: function nsDOMIdentity_raiseAuthenticationFailure(aReason) {
@ -419,7 +458,12 @@ nsDOMIdentity.prototype = {
let message = this.DOMIdentityMessage();
message.reason = aReason;
this._identityInternal._mm.sendAsyncMessage("Identity:IDP:AuthenticationFailure", message);
this._identityInternal._mm.sendAsyncMessage(
"Identity:IDP:AuthenticationFailure",
message,
null,
this._window.document.nodePrincipal
);
},
// Private.
@ -510,7 +554,8 @@ nsDOMIdentity.prototype = {
case "Identity:RP:Watch:OnCancel":
// Do we have a watcher?
if (!this._rpWatcher) {
this._log("WARNING: Received OnCancel message, but there is no RP watcher");
this._log("WARNING: Received OnCancel message, but there is no RP " +
"watcher");
return;
}
@ -520,7 +565,8 @@ nsDOMIdentity.prototype = {
break;
case "Identity:RP:Watch:OnError":
if (!this._rpWatcher) {
this._log("WARNING: Received OnError message, but there is no RP watcher");
this._log("WARNING: Received OnError message, but there is no RP " +
"watcher");
return;
}
@ -593,7 +639,6 @@ nsDOMIdentity.prototype = {
let message = {
errors: []
};
let principal = Ci.nsIPrincipal;
objectCopy(aOptions, message);
@ -603,19 +648,6 @@ nsDOMIdentity.prototype = {
// window origin
message.origin = this._origin;
// On b2g, an app's status can be NOT_INSTALLED, INSTALLED, PRIVILEGED, or
// CERTIFIED. Compare the appStatus value to the constants enumerated in
// Ci.nsIPrincipal.APP_STATUS_*.
message.appStatus = this._appStatus;
// Currently, we only permit certified and privileged apps to use
// Firefox Accounts.
if (aOptions.wantIssuer == "firefox-accounts" &&
this._appStatus !== principal.APP_STATUS_PRIVILEGED &&
this._appStatus !== principal.APP_STATUS_CERTIFIED) {
message.errors.push("ERROR_NOT_AUTHORIZED_FOR_FIREFOX_ACCOUNTS");
}
// Normally the window origin will be the audience in assertions. On b2g,
// certified apps have the power to override this and declare any audience
// the want. Privileged apps can also declare a different audience, as
@ -628,7 +660,7 @@ nsDOMIdentity.prototype = {
// and then post-message the results down to their app.
let _audience = message.origin;
if (message.audience && message.audience != message.origin) {
if (this._appStatus === principal.APP_STATUS_CERTIFIED) {
if (this._appStatus === Ci.nsIPrincipal.APP_STATUS_CERTIFIED) {
_audience = message.audience;
this._log("Certified app setting assertion audience: " + _audience);
} else {
@ -648,7 +680,9 @@ nsDOMIdentity.prototype = {
this._log("nsDOMIdentity uninit() " + this._id);
this._identityInternal._mm.sendAsyncMessage(
"Identity:RP:Unwatch",
{ id: this._id }
{ id: this._id },
null,
this._window.document.nodePrincipal
);
}