Backed out changeset 6580ca3028de (bug 845546) for B2G xpcshell failures on a CLOSED TREE.
authorRyan VanderMeulen <ryanvm@gmail.com>
Wed, 27 Mar 2013 13:01:46 -0400
changeset 126431 56e0d7ad86f281e28e905bc0c90db015e3682cc9
parent 126430 70e442054249c922ae5fa4fc5e25c06159552ac8
child 126432 a3acc0eaed0c64c3da4b81737558e344f1299806
child 126465 27907867002244e79f557a58f764ffea8c1234ea
push id25461
push userryanvm@gmail.com
push dateWed, 27 Mar 2013 17:01:37 +0000
treeherdermozilla-inbound@56e0d7ad86f2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs845546
milestone22.0a1
backs out6580ca3028de2fe920f66751507066dd226a46ef
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out changeset 6580ca3028de (bug 845546) for B2G xpcshell failures on a CLOSED TREE.
browser/base/content/browser-identity.js
browser/base/content/browser.css
browser/base/content/urlbarBindings.xml
browser/base/jar.mn
browser/modules/SignInToWebsite.jsm
dom/identity/DOMIdentity.jsm
dom/identity/nsDOMIdentity.js
modules/libpref/src/init/all.js
toolkit/identity/Identity.jsm
toolkit/identity/IdentityProvider.jsm
toolkit/identity/IdentityUtils.jsm
toolkit/identity/LogUtils.jsm
toolkit/identity/MinimalIdentity.jsm
toolkit/identity/RelyingParty.jsm
toolkit/identity/Sandbox.jsm
toolkit/identity/jwcrypto.jsm
toolkit/identity/tests/unit/head_identity.js
toolkit/identity/tests/unit/test_crypto_service.js
toolkit/identity/tests/unit/test_jwcrypto.js
toolkit/identity/tests/unit/test_log_utils.js
toolkit/identity/tests/unit/test_minimalidentity.js
deleted file mode 100644
--- a/browser/base/content/browser-identity.js
+++ /dev/null
@@ -1,149 +0,0 @@
-/* -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
-/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// This JS shim contains the callbacks to fire DOMRequest events for
-// navigator.pay API within the payment processor's scope.
-
-'use strict';
-
-let { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-
-XPCOMUtils.defineLazyGetter(this, "logger", function() {
-  Cu.import('resource://gre/modules/identity/LogUtils.jsm');
-  return getLogger("Identity", "toolkit.identity.debug");
-});
-
-function IdentityShim() {
-  this.isLoaded = false;
-}
-
-IdentityShim.prototype = {
-  init: function IdentityShim_init() {
-    addMessageListener('identity-delegate-watch', this);
-    addMessageListener('identity-delegate-request', this);
-    addMessageListener('identity-delegate-logout', this);
-    sendAsyncMessage('identity-delegate-loaded');
-    logger.log('init().  sent identity-delegate-complete');
-    this.isLoaded = true;
-  },
-
-  uninit: function IdentityShim_uninit() {
-    if (this.isLoaded) {
-      removeMessageListener('identity-delegate-watch', this);
-      removeMessageListener('identity-delegate-request', this);
-      removeMessageListener('identity-delegate-logout', this);
-      sendAsyncMessage('identity-delegate-complete', null);
-      logger.log('uninit().  sent identity-delegate-complete');
-      this.isLoaded = false;
-    }
-  },
-
-  receiveMessage: function IdentityShim_receiveMessage(aMessage) {
-    switch (aMessage.name) {
-      case 'identity-delegate-watch':
-        this.watch(aMessage.json);
-        break;
-      case 'identity-delegate-request':
-        this.request(aMessage.json);
-        break;
-      case 'identity-delegate-logout':
-        this.logout(aMessage.json);
-        break;
-      default:
-        logger.error("received unexpected message:", aMessage.name);
-        break;
-    }
-  },
-
-  _identityDoMethod: function IdentityShim__identityDoMethod(message) {
-    sendAsyncMessage('identity-service-doMethod', message);
-  },
-
-  _close: function IdentityShim__close() {
-    this.uninit();
-  },
-
-  watch: function IdentityShim_watch(options) {
-    logger.log('doInternalWatch: isLoaded:', this.isLoaded, 'options:', options);
-    if (options) {
-      let BrowserID = content.wrappedJSObject.BrowserID;
-      let callback = function(aParams, aInternalParams) {
-        this._identityDoMethod(aParams);
-        if (aParams.method === 'ready') {
-          this._close();
-        }
-      }.bind(this);
-
-      BrowserID.internal.watch(
-        callback,
-        JSON.stringify(options),
-        function(...things) {
-          logger.log('internal watch returned:', things);
-        }
-      );
-    }
-  },
-
-  request: function IdentityShim_request(options) {
-    logger.log('doInternalRequest: isLoaded:', this.isLoaded, 'options:', options);
-    if (options) {
-      var stringifiedOptions = JSON.stringify(options);
-      let callback = function(assertion, internalParams) {
-        logger.log("received assertion:", assertion);
-        internalParams = internalParams || {};
-        if (assertion) {
-          logger.log("got assertion");
-          this._identityDoMethod({
-            method: 'login',
-            assertion: assertion,
-            _internal: options._internal,
-            _internalParams: internalParams});
-        }
-        this._close();
-      }.bind(this);
-
-      logger.log('call get() with origin', options.origin, ', callback', callback, ', and options', stringifiedOptions);
-      content.wrappedJSObject.BrowserID.internal.get(
-        options.origin,
-        callback,
-        stringifiedOptions
-      );
-      logger.log('called get()');
-    }
-  },
-
-  logout: function IdentityShim_logout(options) {
-    logger.log('doInternalLogout: isLoaded:', this.isLoaded, 'options:', options);
-    if (options) {
-      let BrowserID = content.wrappedJSObject.BrowserID;
-      let callback = function() {
-        this._identityDoMethod({method: 'logout', _internal: options._internal});
-        this._close();
-      }.bind(this);
-
-      BrowserID.internal.logout(options.origin, callback);
-    }
-  }
-};
-
-this.shim = null;
-
-addEventListener('DOMContentLoaded', function(e) {
-  content.addEventListener('load', function(e) {
-    logger.log('content loaded');
-    this.shim = new IdentityShim();
-    this.shim.init();
-  });
-});
-
-content.addEventListener('beforeunload', function(e) {
-  if (this.shim) {
-    this.shim.uninit();
-  }
-});
-
-
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -262,16 +262,36 @@ panel[noactions] > richlistbox > richlis
 #urlbar[pageproxystate="invalid"] > #urlbar-icons > .urlbar-icon:not(#go-button),
 #urlbar[pageproxystate="valid"] > #urlbar-icons > #go-button,
 #urlbar[pageproxystate="invalid"][focused="true"] > #urlbar-go-button ~ toolbarbutton,
 #urlbar[pageproxystate="valid"] > #urlbar-go-button,
 #urlbar:not([focused="true"]) > #urlbar-go-button {
   visibility: collapse;
 }
 
+#urlbar[pageproxystate="invalid"] > #identity-box > #identity-icon-labels {
+  visibility: collapse;
+}
+
+#urlbar[pageproxystate="invalid"] > #identity-box {
+  pointer-events: none;
+}
+
+#identity-icon-labels {
+  max-width: 18em;
+}
+
+#identity-icon-country-label {
+  direction: ltr;
+}
+
+#identity-box.verifiedIdentity > #identity-icon-labels > #identity-icon-label {
+  -moz-margin-end: 0.25em !important;
+}
+
 #wrapper-search-container > #search-container > #searchbar > .searchbar-textbox > .autocomplete-textbox-container > .textbox-input-box > html|*.textbox-input {
   visibility: hidden;
 }
 
 /* ::::: Unified Back-/Forward Button ::::: */
 #back-button > .toolbarbutton-menu-dropmarker,
 #forward-button > .toolbarbutton-menu-dropmarker {
   display: none;
@@ -333,16 +353,26 @@ window[chromehidden~="toolbar"] toolbar:
   overflow-y: visible !important;
 }
 
 #sync-notifications notification {
   -moz-binding: url("chrome://browser/content/sync/notification.xml#notification");
 }
 %endif
 
+/* Identity UI */
+#identity-popup-content-box.unknownIdentity > #identity-popup-connectedToLabel ,
+#identity-popup-content-box.unknownIdentity > #identity-popup-runByLabel ,
+#identity-popup-content-box.unknownIdentity > #identity-popup-content-host ,
+#identity-popup-content-box.unknownIdentity > #identity-popup-content-owner ,
+#identity-popup-content-box.verifiedIdentity > #identity-popup-connectedToLabel2 ,
+#identity-popup-content-box.verifiedDomain > #identity-popup-connectedToLabel2 {
+  display: none;
+}
+
 /*  Full Screen UI */
 
 #fullscr-toggler {
   height: 1px;
   background: black;
 }
 
 #full-screen-warning-container {
--- a/browser/base/content/urlbarBindings.xml
+++ b/browser/base/content/urlbarBindings.xml
@@ -1117,70 +1117,264 @@
       <method name="onDownloadEnded">
         <body><![CDATA[
           this.updateProgress();
         ]]></body>
       </method>
     </implementation>
   </binding>
 
-  <binding 
-    id="identity-request-notification" 
-    extends="chrome://global/content/bindings/notification.xml#popup-notification">
+  <binding id="identity-request-notification" extends="chrome://global/content/bindings/notification.xml#popup-notification">
+    <content align="start">
 
-    <content>
-      <panel id="persona-container" anonid="persona-container" flex="1" />
-    </content>
+      <xul:image class="popup-notification-icon"
+                 xbl:inherits="popupid,src=icon"/>
 
-    <implementation implements="nsIObserver, nsIDOMEventListener">
+      <xul:vbox flex="1">
+        <xul:vbox anonid="identity-deck">
+          <xul:vbox flex="1" pack="center"> <!-- 1: add an email -->
+            <html:input type="email" anonid="email" required="required" size="30"/>
+            <xul:description anonid="newidentitydesc"/>
+            <xul:spacer flex="1"/>
+            <xul:label class="text-link custom-link small-margin" anonid="chooseemail" hidden="true"/>
+          </xul:vbox>
+          <xul:vbox flex="1" hidden="true"> <!-- 2: choose an email -->
+            <xul:description anonid="chooseidentitydesc"/>
+            <xul:radiogroup anonid="identities">
+            </xul:radiogroup>
+            <xul:label class="text-link custom-link" anonid="newemail"/>
+          </xul:vbox>
+        </xul:vbox>
+        <xul:hbox class="popup-notification-button-container"
+                  pack="end" align="center">
+          <xul:label anonid="tos" class="text-link" hidden="true"/>
+          <xul:label anonid="privacypolicy" class="text-link" hidden="true"/>
+          <xul:spacer flex="1"/>
+          <xul:image anonid="throbber" src="chrome://browser/skin/tabbrowser/loading.png"
+                     style="visibility:hidden" width="16" height="16"/>
+          <xul:button anonid="button"
+                      type="menu-button"
+                      class="popup-notification-menubutton"
+                      xbl:inherits="oncommand=buttoncommand,label=buttonlabel,accesskey=buttonaccesskey">
+            <xul:menupopup anonid="menupopup"
+                           xbl:inherits="oncommand=menucommand">
+              <children/>
+              <xul:menuitem class="menuitem-iconic popup-notification-closeitem"
+                            label="&closeNotificationItem.label;"
+                            xbl:inherits="oncommand=closeitemcommand"/>
+            </xul:menupopup>
+          </xul:button>
+        </xul:hbox>
+      </xul:vbox>
+      <xul:vbox pack="start">
+        <xul:toolbarbutton anonid="closebutton"
+                           class="messageCloseButton popup-notification-closebutton tabbable"
+                           xbl:inherits="oncommand=closebuttoncommand"
+                           tooltiptext="&closeNotification.tooltip;"/>
+      </xul:vbox>
+    </content>
+    <implementation>
       <constructor><![CDATA[
-        dump(" ** in identity xul constructor\n");
-        this.complete = false;
-
-        // Mark outgoing messages with the id of the caller
-        this.messageSubject = Components.classes["@mozilla.org/supports-string;1"]
-          .createInstance(Components.interfaces.nsISupportsString);
-        this.messageSubject.data = this.notification.options.context.id;
+        // this.notification.options.identity is used to pass identity-specific info to the binding
+        let origin = this.identity.origin
 
-        // adopt the iframe and display it in the panel
-        // XXX this does not work in FF3.6 or older
-        let personaIframe = this.notification.options.context.iframe;
-        let node = document.adoptNode(personaIframe);
-        let panel = document.getAnonymousElementByAttribute(this, "anonid", "persona-container");
-        panel.appendChild(node);
+        // Populate text
+        this.emailField.placeholder = gNavigatorBundle.
+                                      getString("identity.newIdentity.email.placeholder");
+        this.newIdentityDesc.textContent = gNavigatorBundle.getFormattedString(
+                                             "identity.newIdentity.description", [origin]);
+        this.chooseIdentityDesc.textContent = gNavigatorBundle.getFormattedString(
+                                                "identity.chooseIdentity.description", [origin]);
 
-        // The dimensions of the panel are modified dynamically by
-        // SignInToWebsite.jsm.
+        // Show optional terms of service and privacy policy links
+        this._populateLink(this.identity.termsOfService, "tos", "identity.termsOfService");
+        this._populateLink(this.identity.privacyPolicy, "privacypolicy", "identity.privacyPolicy");
+
+        // Populate the list of identities to choose from. The origin is used to provide
+        // better suggestions.
+        let identities = this.SignInToWebsiteUX.getIdentitiesForSite(origin);
+
+        this._populateIdentityList(identities);
 
-        dump(" ** Persona host iframe attached to xul panel\n");
+        if (typeof this.step == "undefined") {
+          // First opening of this notification
+          // Show the add email pane (0) if there are no existing identities otherwise show the list
+          this.step = "result" in identities && identities.result.length ? 1 : 0;
+        } else {
+          // Already opened so restore previous state
+          if (this.identity.typedEmail) {
+            this.emailField.value = this.identity.typedEmail;
+          }
+          if (this.identity.selected) {
+            // If the user already chose an identity then update the UI to reflect that
+            this.onIdentitySelected();
+          }
+          // Update the view for the step
+          this.step = this.step;
+        }
 
-        // Listen to messages from SignInToWebsite.jsm
-        Services.obs.addObserver(this, "identity-delegate-ui-close", false);
+        // Fire notification with the chosen identity when main button is clicked
+        this.button.addEventListener("command", this._onButtonCommand.bind(this), true);
 
-        // message back to SignInToWebsite that we've started
-        // and the flow with the given id can go ahead
-        // XXX we might not need this
-        Services.obs.notifyObservers(this.messageSubject, "identity-delegate-ui-open", null);
+        // Do the same if enter is pressed in the email field
+        this.emailField.addEventListener("keypress", function emailFieldKeypress(aEvent) {
+          if (aEvent.keyCode != aEvent.DOM_VK_RETURN)
+            return;
+          this._onButtonCommand(aEvent);
+        }.bind(this));
+
+        this.addEmailLink.value = gNavigatorBundle.getString("identity.newIdentity.label");
+        this.addEmailLink.accessKey = gNavigatorBundle.getString("identity.newIdentity.accessKey");
+        this.addEmailLink.addEventListener("click", function addEmailClick(evt) {
+          this.step = 0;
+        }.bind(this));
+
+        this.chooseEmailLink.value = gNavigatorBundle.getString("identity.chooseIdentity.label");
+        this.chooseEmailLink.hidden = !("result" in identities && identities.result.length);
+        this.chooseEmailLink.addEventListener("click", function chooseEmailClick(evt) {
+          this.step = 1;
+        }.bind(this));
+
+        this.emailField.addEventListener("blur", function onEmailBlur() {
+          this.identity.typedEmail = this.emailField.value;
+        }.bind(this));
       ]]></constructor>
 
-      <destructor><![CDATA[
-        if (!this.complete) {
-          Services.obs.notifyObservers(this.messageSubject, "identity-delegate-canceled", null);
-        }
-        Services.obs.removeObserver(this, "identity-delegate-ui-close", false);
-      ]]></destructor>
+      <field name="SignInToWebsiteUX" readonly="true">
+        let sitw = {};
+        Components.utils.import("resource:///modules/SignInToWebsite.jsm", sitw);
+        sitw.SignInToWebsiteUX;
+      </field>
+
+      <field name="newIdentityDesc" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "newidentitydesc");
+      </field>
+
+      <field name="chooseIdentityDesc" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "chooseidentitydesc");
+      </field>
+
+      <field name="identityList" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "identities");
+      </field>
+
+      <field name="emailField" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "email");
+      </field>
+
+      <field name="addEmailLink" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "newemail");
+      </field>
+
+      <field name="chooseEmailLink" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "chooseemail");
+      </field>
+
+      <field name="throbber" readonly="true">
+        document.getAnonymousElementByAttribute(this, "anonid", "throbber");
+      </field>
+
+      <field name="identity" readonly="true">
+        this.notification.options.identity;
+      </field>
+
+      <!-- persist the state on the identity object so we can re-create the
+           notification state upon re-opening -->
+      <property name="step">
+        <getter>
+          return this.identity.step;
+        </getter>
+        <setter><![CDATA[
+          let deck = document.getAnonymousElementByAttribute(this, "anonid", "identity-deck");
+          for (let i = 0; i < deck.children.length; i++) {
+            deck.children[i].hidden = (val != i);
+          }
+          this.identity.step = val;
+          switch (val) {
+            case 0:
+              this.emailField.focus();
+              break;
+          }]]>
+        </setter>
+      </property>
 
-      <method name="observe">
-        <parameter name="aSubject"/>
-        <parameter name="aTopic"/>
-        <parameter name="aData"/>
+      <method name="onIdentitySelected">
+        <body><![CDATA[
+          this.throbber.style.visibility = "visible";
+          this.button.disabled = true;
+          this.emailField.value = this.identity.selected
+          this.emailField.disabled = true;
+          this.identityList.disabled = true;
+        ]]></body>
+      </method>
+
+      <method name="_populateLink">
+        <parameter name="aURL"/>
+        <parameter name="aLinkId"/>
+        <parameter name="aStringId"/>
+        <body><![CDATA[
+          if (aURL) {
+            // Show optional link to aURL
+            let link = document.getAnonymousElementByAttribute(this, "anonid", aLinkId);
+            link.value = gNavigatorBundle.getString(aStringId);
+            link.href = aURL;
+            link.hidden = false;
+          }
+        ]]></body>
+      </method>
+
+      <method name="_populateIdentityList">
+        <parameter name="aIdentities"/>
         <body><![CDATA[
-          // The only message we observe is identity-delegate-ui-close
-          this.complete = true;
-          this.notification.remove();
+          let foundLastUsed = false;
+          let lastUsed = this.identity.selected || aIdentities.lastUsed;
+          for (let id in aIdentities.result) {
+            let label = aIdentities.result[id];
+            let opt = this.identityList.appendItem(label);
+            if (label == lastUsed) {
+              this.identityList.selectedItem = opt;
+              foundLastUsed = true;
+            }
+          }
+          if (!foundLastUsed) {
+            this.identityList.selectedIndex = -1;
+          }
+        ]]></body>
+      </method>
+
+      <method name="_onButtonCommand">
+        <parameter name="aEvent"/>
+        <body><![CDATA[
+          if (aEvent.target != aEvent.currentTarget)
+            return;
+          let chosenId;
+          switch (this.step) {
+            case 0:
+              aEvent.stopPropagation();
+              if (!this.emailField.validity.valid) {
+                this.emailField.focus();
+                return;
+              }
+              chosenId = this.emailField.value;
+              break;
+            case 1:
+              aEvent.stopPropagation();
+              let selectedItem = this.identityList.selectedItem
+              chosenId = selectedItem ? selectedItem.label : null;
+              if (!chosenId)
+                return;
+              break;
+            default:
+              throw new Error("Unknown case");
+              return;
+          }
+          // Actually select the identity
+          this.SignInToWebsiteUX.selectIdentity(this.identity.rpId, chosenId);
+          this.identity.selected = chosenId;
+          this.onIdentitySelected();
         ]]></body>
       </method>
 
     </implementation>
   </binding>
 
   <binding id="center-item">
     <content align="center">
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -55,17 +55,16 @@ browser.jar:
         content/browser/abouthealthreport/abouthealth.css     (content/abouthealthreport/abouthealth.css)
 #endif
         content/browser/aboutRobots-icon.png          (content/aboutRobots-icon.png)
         content/browser/aboutRobots-widget-left.png   (content/aboutRobots-widget-left.png)
         content/browser/aboutSocialError.xhtml        (content/aboutSocialError.xhtml)
 *       content/browser/browser.css                   (content/browser.css)
 *       content/browser/browser.js                    (content/browser.js)
 *       content/browser/browser.xul                   (content/browser.xul)
-        content/browser/browser-identity.js           (content/browser-identity.js)
 *       content/browser/browser-tabPreviews.xml       (content/browser-tabPreviews.xml)
         content/browser/content.js                    (content/content.js)
         content/browser/newtab/newTab.xul             (content/newtab/newTab.xul)
 *       content/browser/newtab/newTab.js              (content/newtab/newTab.js)
         content/browser/newtab/newTab.css             (content/newtab/newTab.css)
         content/browser/newtab/preload.xhtml          (content/newtab/preload.xhtml)
 *       content/browser/pageinfo/pageInfo.xul         (content/pageinfo/pageInfo.xul)
 *       content/browser/pageinfo/pageInfo.js          (content/pageinfo/pageInfo.js)
--- a/browser/modules/SignInToWebsite.jsm
+++ b/browser/modules/SignInToWebsite.jsm
@@ -1,445 +1,247 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-'use strict';
+"use strict";
 
-this.EXPORTED_SYMBOLS = ['SignInToWebsiteUX'];
+this.EXPORTED_SYMBOLS = ["SignInToWebsiteUX"];
 
 const Cc = Components.classes;
 const Ci = Components.interfaces;
 const Cu = Components.utils;
 
-Cu.import('resource://gre/modules/Services.jsm');
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/identity/IdentityUtils.jsm');
-
-const kIdentityScreen = 'https://picl.personatest.org/sign_in#NATIVE';
-const kIdentityFrame = 'https://picl.personatest.org/communication_iframe';
-const kIdentityShim = 'chrome://browser/content/browser-identity.js';
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
-const PANEL_MIN_HEIGHT = 440;
-const PANEL_MIN_WIDTH = 300;
-
-XPCOMUtils.defineLazyModuleGetter(this, 'IdentityService',
-                                  'resource://gre/modules/identity/MinimalIdentity.jsm');
-
-XPCOMUtils.defineLazyGetter(this, "logger", function() {
-  Cu.import('resource://gre/modules/identity/LogUtils.jsm');
-  return getLogger("Identity", "toolkit.identity.debug");
-});
+XPCOMUtils.defineLazyModuleGetter(this, "IdentityService",
+                                  "resource://gre/modules/identity/Identity.jsm");
 
-/**
- * Ripped off from the resize watcher in base/content/browser-social.js
- */
-
-function sizePanelToContent(iframe) {
-  // FIXME: bug 764787: Maybe we can use nsIDOMWindowUtils.getRootBounds() here?
-  let doc = iframe.contentDocument;
-  if (!doc || !doc.body) {
-    return;
-  }
-  let body = doc.body;
+XPCOMUtils.defineLazyModuleGetter(this, "Logger",
+                                  "resource://gre/modules/identity/LogUtils.jsm");
 
-  // offsetHeight/Width don't include margins, so account for that.
-  let cs = doc.defaultView.getComputedStyle(body);
-  let computedHeight = parseInt(cs.marginTop) + body.offsetHeight + parseInt(cs.marginBottom);
-  let height = Math.max(computedHeight, PANEL_MIN_HEIGHT);
-  let computedWidth = parseInt(cs.marginLeft) + body.offsetWidth + parseInt(cs.marginRight);
-  let width = Math.max(computedWidth, PANEL_MIN_WIDTH);
-
-  // The panel can only resize vertically; otherwise, we would have to
-  // compensate for leftward or rightward shifts here
-  iframe.style.height = height + "px";
-  iframe.style.width = width + "px";
+function log(...aMessageArgs) {
+  Logger.log.apply(Logger, ["SignInToWebsiteUX"].concat(aMessageArgs));
 }
 
-function ResizeWatcher(iframe) {
-  this._mutationObserver = null;
-  this._iframe = iframe;
+this.SignInToWebsiteUX = {
 
-  this.start();
-}
-
-ResizeWatcher.prototype = {
-  start: function ResizeWatcher_start() {
-    this.stop(); // just in case...
-    let doc = this._iframe.contentDocument;
+  init: function SignInToWebsiteUX_init() {
 
-    this._mutationObserver = new this._iframe.contentWindow.MutationObserver(
-      function(mutations) {
-        sizePanelToContent(this._iframe);
-      }.bind(this));
-
-    // Observe anything that causes the size to change.
-    let config = {
-      attributes: true,
-      characterData: true,
-      childList: true,
-      subtree: true
-    };
-
-    this._mutationObserver.observe(doc, config);
-
-    // and since this may be setup after the load event has fired we do an
-    // initial resize now.
-    sizePanelToContent(this._iframe);
+    /*
+     * bug 793906 - temporarily disabling desktop UI so we can
+     * focus on b2g without worrying about desktop as well
+     *
+    Services.obs.addObserver(this, "identity-request", false);
+    Services.obs.addObserver(this, "identity-auth", false);
+    Services.obs.addObserver(this, "identity-auth-complete", false);
+    Services.obs.addObserver(this, "identity-login-state-changed", false);
+     */
   },
 
-  stop: function ResizeWatcher_stop() {
-    if (this._mutationObserver) {
-      try {
-        this._mutationObserver.disconnect();
-      } catch (ex) {
-        // may get "TypeError: can't access dead object" which seems strange,
-        // but doesn't seem to indicate a real problem, so ignore it...
-      }
-      this._mutationObserver = null;
-    }
-  }
-};
-
-/**
- * Return the chrome window and <browser> for the given outer window ID.
- */
-function getUIForWindowID(aWindowId) {
-  let someWindow = Services.wm.getMostRecentWindow('navigator:browser');
-  if (!someWindow) {
-    logger.error('SignInToWebsiteUX', 'no window');
-    return {};
-  }
-
-  let windowUtils = someWindow.QueryInterface(Ci.nsIInterfaceRequestor)
-                              .getInterface(Ci.nsIDOMWindowUtils);
-  let content = windowUtils.getOuterWindowWithId(aWindowId);
-
-  if (content) {
-    let browser = content.QueryInterface(Ci.nsIInterfaceRequestor)
-                         .getInterface(Ci.nsIWebNavigation)
-                         .QueryInterface(Ci.nsIDocShell).chromeEventHandler;
-    //let browser = someWindow.gBrowser;
-    let chromeWin = browser.ownerDocument.defaultView;
-
-    return {
-      content: content,
-      browser: browser,
-      chromeWin: chromeWin
-    };
-  }
-  logger.error('SignInToWebsiteUX', 'no content');
-
-  return {};
-}
-
-function requestUI(aContext) {
-  logger.log('requestUI for windowId', aContext.id);
-  let UI = getUIForWindowID(aContext.id);
-
-  // message is not shown in the UI but is required
-  let mainAction = {
-    label: UI.chromeWin.gNavigatorBundle.getString('identity.next.label'),
-    accessKey: UI.chromeWin.gNavigatorBundle.getString('identity.next.accessKey'),
-    callback: function() {} // required
-  };
-  let secondaryActions = [];
-  let options = {
-    context: aContext
-  };
-
-  UI.chromeWin.PopupNotifications.show(UI.browser,
-                                       'identity-request', aContext.id,
-                                       'identity-notification-icon', mainAction,
-                                       [], options);
-}
-
-function HostFrame() {
-  this._iframe = null;
-  this._resizeWatcher = null;
-}
-
-HostFrame.prototype = {
-  /*
-   * getIframe - adds iframe to aOptions
-   */
-  getIframe: function HostFrame_getIframe(aOptions, aCallback) {
-    if (this._gotIframe) {
-      logger.error("Can only get iframe once with HostFrame helper");
-      return;
-    }
-
-    this._createIframe(aOptions);
-    aCallback();
+  uninit: function SignInToWebsiteUX_uninit() {
+    /*
+     * As above:
+     * bug 793906 - temporarily disabling desktop UI so we can
+     * focus on b2g without worrying about desktop as well
+     *
+    Services.obs.removeObserver(this, "identity-request");
+    Services.obs.removeObserver(this, "identity-auth");
+    Services.obs.removeObserver(this, "identity-auth-complete");
+    Services.obs.removeObserver(this, "identity-login-state-changed");
+     */
   },
 
-  cleanUp: function HostFrame_cleanUp() {
-    if (this._resizeWatcher) {
-      this._resizeWatcher.stop();
+  observe: function SignInToWebsiteUX_observe(aSubject, aTopic, aData) {
+    log("observe: received", aTopic, "with", aData, "for", aSubject);
+    let options = null;
+    if (aSubject) {
+      options = aSubject.wrappedJSObject;
     }
-  },
-
-  /*
-   * create an iframe and insert it into aOptions.  If showUI is
-   * true, attach the iframe to a xul panel in the popup notification.
-   * Otherwise attach to a hidden document.
-   */
-  _createIframe: function HostFrame_createIframe(aOptions) {
-    let srcURI = aOptions.showUI ? kIdentityScreen : kIdentityFrame;
-    logger.log('showUI is', aOptions.showUI, 'so iframe src =', srcURI);
-
-    let hiddenDoc = Services.appShell.hiddenDOMWindow.document;
-    this._iframe = hiddenDoc.createElementNS('http://www.w3.org/1999/xhtml', 'iframe');
-
-    this._iframe.setAttribute('mozbrowser', true);
-    this._iframe.setAttribute('mozframetype', 'content');
-    this._iframe.setAttribute('type', 'content');
-    this._iframe.setAttribute('remote', true);
-    this._iframe.setAttribute('id', 'persona-host-frame');
-    this._iframe.setAttribute('src', srcURI);
-
-    // implement a dynamic resize watcher a la Social API
-    this._iframe.style.height = "440px";
-    this._iframe.style.width = "300px";
-
-    aOptions.iframe = this._iframe;
-
-    if (aOptions.showUI) {
-      // synchronous, so we can call _injectShim below with no race condition
-      requestUI(aOptions);
-      this._resizeWatcher = new ResizeWatcher(this._iframe);
-    } else {
-      hiddenDoc.documentElement.appendChild(this._iframe);
-    }
-    this._injectShim(this._iframe);
-  },
-
-  _injectShim: function HostFrame_injectShim(aIframe) {
-    let mm = aIframe.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager;
-    logger.log('loadFrameScript:', kIdentityShim);
-    mm.loadFrameScript(kIdentityShim, true);
-  }
-};
-
-function Pipe(aOptions, aController) {
-  this.options = aOptions;
-  this.controller = aController;
-  this.mm = null;
-  this._closed = false;
-  return this;
-}
-
-Pipe.prototype = {
-  observe: function pipe_observe(aSubject, aTopic, aData) {
-    logger.log('pipe observed', aTopic);
-    switch (aTopic) {
-      case 'identity-delegate-canceled':
-        this._close();
-        this.controller.serviceDoMethod({method: 'cancel'}, this.options.id);
+    switch(aTopic) {
+      case "identity-request":
+        this.requestLogin(options);
+        break;
+      case "identity-auth":
+        this._openAuthenticationUI(aData, options);
+        break;
+      case "identity-auth-complete":
+        this._closeAuthenticationUI(aData);
         break;
-
+      case "identity-login-state-changed":
+        let emailAddress = aData;
+        if (emailAddress) {
+          this._removeRequestUI(options);
+          this._showLoggedInUI(emailAddress, options);
+        } else {
+          this._removeLoggedInUI(options);
+        }
+        break;
       default:
-        logger.error('pipe observed unexpected topic: ' + aTopic);
+        Logger.reportError("SignInToWebsiteUX", "Unknown observer notification:", aTopic);
         break;
     }
   },
 
-  _close: function pipe__delegateClose() {
-    this._closed = true;
-    Services.obs.removeObserver(this, 'identity-delegate-canceled');
-    if (this.mm) {
-      this.mm.removeMessageListener('identity-service-doMethod', this._serviceDoMethod);
-      this.mm.removeMessageListener('identity-delegate-complete', this._delegateComplete);
-      this.mm.removeMessageListener('identity-delegate-loaded', this._delegateLoaded);
-    }
-    let subject = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString);
-    subject.data = this.options.id;
-    Services.obs.notifyObservers(subject, 'identity-delegate-ui-close', null);
-
-    if (typeof this.options.onComplete === 'function') {
-      this.options.onComplete();
-    }
-  },
+  /**
+   * The website is requesting login so the user must choose an identity to use.
+   */
+  requestLogin: function SignInToWebsiteUX_requestLogin(aOptions) {
+    let windowID = aOptions.rpId;
+    log("requestLogin", aOptions);
+    let [chromeWin, browserEl] = this._getUIForWindowID(windowID);
 
-  _delegateLoaded: function pipe__delegateLoaded() {
-    this.mm.sendAsyncMessage(this.options.message, this.options.rpOptions);
-    //this.resizer = new DynamicResizeWatcher();
-    //this.resizer.start(
-  },
-
-  _delegateComplete: function pipe__delegateComplete() {
-    this._close();
-  },
+    // message is not shown in the UI but is required
+    let message = aOptions.origin;
+    let mainAction = {
+      label: chromeWin.gNavigatorBundle.getString("identity.next.label"),
+      accessKey: chromeWin.gNavigatorBundle.getString("identity.next.accessKey"),
+      callback: function() {}, // required
+    };
+    let options = {
+      identity: {
+        origin: aOptions.origin,
+      },
+    };
+    let secondaryActions = [];
 
-  _serviceDoMethod: function pipe__doMethod(aMethodOptions) {
-    let message = aMethodOptions.json;
-    if (typeof message === 'string') {
-      try {
-        message = JSON.parse(message);
-      } catch (err) {
-        logger.error('Bad json message: ' + message);
-        return;
-      }
+    // add some extra properties to the notification to store some identity-related state
+    for (let opt in aOptions) {
+      options.identity[opt] = aOptions[opt];
     }
-    this.controller.serviceDoMethod(message, this.options.id);
+    log("requestLogin: rpId: ", options.identity.rpId);
+
+    chromeWin.PopupNotifications.show(browserEl, "identity-request", message,
+                                      "identity-notification-icon", mainAction,
+                                      [], options);
   },
 
-  communicate: function pipe_communicate() {
-    if (this._closed) {
-      logger.error('Cannot communicate with persona frame; pipe already closed');
-      return;
-    }
-    Services.obs.addObserver(this, 'identity-delegate-canceled', false);
-
-    let frameLoader = this.options.iframe.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
-    if (frameLoader) {
-      this.mm = frameLoader.messageManager;
-      this.mm.addMessageListener('identity-service-doMethod', this._serviceDoMethod.bind(this));
-      this.mm.addMessageListener('identity-delegate-loaded', this._delegateLoaded.bind(this));
-      this.mm.addMessageListener('identity-delegate-complete', this._delegateComplete.bind(this));
-    } else {
-      logger.error('FrameLoader unavailable; Frame did not get attached properly?');
-    }
-  }
-};
-
-this.SignInToWebsiteUX = {
-  init: function SignInToWebsiteUX_init() {
-    this.contexts = {};
-    Services.obs.addObserver(this, 'identity-controller-watch', false);
-    Services.obs.addObserver(this, 'identity-controller-request', false);
-    Services.obs.addObserver(this, 'identity-controller-logout', false);
-    Services.obs.addObserver(this, 'identity-controller-canceled', false);
+  /**
+   * Get the list of possible identities to login to the given origin.
+   */
+  getIdentitiesForSite: function SignInToWebsiteUX_getIdentitiesForSite(aOrigin) {
+    return IdentityService.RP.getIdentitiesForSite(aOrigin);
   },
 
-  uninit: function SignInToWebsiteUX_uninit() {
-    Services.obs.removeObserver(this, 'identity-controller-watch');
-    Services.obs.removeObserver(this, 'identity-controller-request');
-    Services.obs.removeObserver(this, 'identity-controller-logout');
-    Services.obs.removeObserver(this, 'identity-controller-canceled');
+  /**
+   * User chose a new or existing identity from the doorhanger after a request() call
+   */
+  selectIdentity: function SignInToWebsiteUX_selectIdentity(aRpId, aIdentity) {
+    log("selectIdentity: rpId: ", aRpId, " identity: ", aIdentity);
+    IdentityService.selectIdentity(aRpId, aIdentity);
   },
 
-  observe: function SignInToWebsiteUX_observe(aSubject, aTopic, aData) {
-    logger.log('controller observed:', aTopic);
-    // XXX need to detect page unload of any of our flows
-    // XXX we get strings from xul, and objects from elsewhere
-    let rpOptions = {};
-    if (aSubject) {
-      if (aSubject.wrappedJSObject) {
-        rpOptions = aSubject.wrappedJSObject;
-      } else {
-        rpOptions = {id: aSubject.QueryInterface(Ci.nsISupportsString).data};
-      }
-    }
-    if (!rpOptions.id) {
-      logger.error('Got a message with no RP id');
-      return;
+  // Private
+
+  /**
+   * Return the chrome window and <browser> for the given outer window ID.
+   */
+  _getUIForWindowID: function(aWindowID) {
+    let someWindow = Services.wm.getMostRecentWindow("navigator:browser");
+    if (!someWindow) {
+      Logger.reportError("SignInToWebsiteUX", "no window");
+      return [null, null];
     }
 
-    let rpId = rpOptions.id;
-    let UI = getUIForWindowID(rpId);
+    let windowUtils = someWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                                .getInterface(Ci.nsIDOMWindowUtils);
+    let content = windowUtils.getOuterWindowWithId(aWindowID);
 
-    let options = {
-      id: rpOptions.id,
-      rpOptions: rpOptions
-    };
+    if (content) {
+      let browser = content.QueryInterface(Ci.nsIInterfaceRequestor)
+                           .getInterface(Ci.nsIWebNavigation)
+                           .QueryInterface(Ci.nsIDocShell).chromeEventHandler;
+      let chromeWin = browser.ownerDocument.defaultView;
+      return [chromeWin, browser];
+    }
+    Logger.reportError("SignInToWebsiteUX", "no content");
 
-    switch (aTopic) {
-      case 'identity-controller-watch':
-        this.doWatch(options);
-        break;
+    return [null, null];
+  },
 
-      case 'identity-controller-request':
-        this.doRequest(options);
-        break;
+  /**
+   * Open UI with a content frame displaying aAuthURI so that the user can authenticate with their
+   * IDP.  Then tell Identity.jsm the identifier for the window so that it knows that the DOM API
+   * calls are for this authentication flow.
+   */
+  _openAuthenticationUI: function _openAuthenticationUI(aAuthURI, aContext) {
+    // Open a tab/window with aAuthURI with an identifier (aID) attached so that the DOM APIs know this is an auth. window.
+    let chromeWin = Services.wm.getMostRecentWindow('navigator:browser');
+    let features = "chrome=false,width=640,height=480,centerscreen,location=yes,resizable=yes,scrollbars=yes,status=yes";
+    log("aAuthURI: ", aAuthURI);
+    let authWin = Services.ww.openWindow(chromeWin, "about:blank", "", features, null);
+    let windowID = authWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
+    log("authWin outer id: ", windowID);
 
-      case 'identity-controller-logout':
-        this.doLogout(options);
-        break;
+    let provId = aContext.provId;
+    // Tell the ID service about the id before loading the url
+    IdentityService.IDP.setAuthenticationFlow(windowID, provId);
+
+    authWin.location = aAuthURI;
+  },
 
-      default:
-        logger.error('SignInToWebsiteUX', 'Unknown observer notification:', aTopic);
-        break;
-    }
+  _closeAuthenticationUI: function _closeAuthenticationUI(aAuthId) {
+    log("_closeAuthenticationUI:", aAuthId);
+    let [chromeWin, browserEl] = this._getUIForWindowID(aAuthId);
+    if (chromeWin)
+      chromeWin.close();
+    else
+      Logger.reportError("SignInToWebsite", "Could not close window with ID", aAuthId);
   },
 
-  serviceDoMethod: function SignInToWebsiteUX_doMethod(aMessage, aId) {
-    logger.log('serviceDoMethod received:', aMessage);
-    switch (aMessage.method) {
-      case 'ready':
-        IdentityService.doReady(aId);
-        break;
+  /**
+   * Show a doorhanger indicating the currently logged-in user.
+   */
+  _showLoggedInUI: function _showLoggedInUI(aIdentity, aContext) {
+    let windowID = aContext.rpId;
+    log("_showLoggedInUI for ", windowID);
+    let [chromeWin, browserEl] = this._getUIForWindowID(windowID);
 
-      case 'login':
-        if (aMessage._internalParams) {
-          IdentityService.doLogin(aId, aMessage.assertion, aMessage._internalParams);
-        } else {
-          IdentityService.doLogin(aId, aMessage.assertion);
-        }
-        break;
-
-      case 'logout':
-        IdentityService.doLogout(aId);
-        break;
-
-      case 'cancel':
-        IdentityService.doCancel(aId);
-        break;
-
-      default:
-        logger.error('Unknown identity method: ' + aMessage.method);
-        break;
-    }
+    let message = chromeWin.gNavigatorBundle.getFormattedString("identity.loggedIn.description",
+                                                          [aIdentity]);
+    let mainAction = {
+      label: chromeWin.gNavigatorBundle.getString("identity.loggedIn.signOut.label"),
+      accessKey: chromeWin.gNavigatorBundle.getString("identity.loggedIn.signOut.accessKey"),
+      callback: function() {
+        log("sign out callback fired");
+        IdentityService.RP.logout(windowID);
+      },
+    };
+    let secondaryActions = [];
+    let options = {
+      dismissed: true,
+    };
+    let loggedInNot = chromeWin.PopupNotifications.show(browserEl, "identity-logged-in", message,
+                                                  "identity-notification-icon", mainAction,
+                                                  secondaryActions, options);
+    loggedInNot.rpId = windowID;
   },
 
-  cleanUp: function SignInToWebsiteUX_cleanUp(aId) {
-    let context = this.contexts[aId];
-    if (context) {
-      if (context.hostFrame) {
-        context.hostFrame.cleanUp();
-      }
-      if (context.iframe && context.iframe.parentNode) {
-        logger.log("removing iframe from parent node and deleting it");
-        context.iframe.parentNode.removeChild(context.iframe);
-        delete context.iframe;
-      }
-      this.contexts[aId] = {};
-      delete this.contexts[aId];
-    }
+  /**
+   * Remove the doorhanger indicating the currently logged-in user.
+   */
+  _removeLoggedInUI: function _removeLoggedInUI(aContext) {
+    let windowID = aContext.rpId;
+    log("_removeLoggedInUI for ", windowID);
+    if (!windowID)
+      throw "_removeLoggedInUI: Invalid RP ID";
+    let [chromeWin, browserEl] = this._getUIForWindowID(windowID);
+
+    let loggedInNot = chromeWin.PopupNotifications.getNotification("identity-logged-in", browserEl);
+    if (loggedInNot)
+      chromeWin.PopupNotifications.remove(loggedInNot);
   },
 
-  delegate: function SignInToWebsiteUX_delegate(aOptions) {
-    let hostFrame = new HostFrame();
-    hostFrame.getIframe(aOptions, function() {
-      // iframe has been added to aOptions
+  /**
+   * Remove the doorhanger indicating the currently logged-in user.
+   */
+  _removeRequestUI: function _removeRequestUI(aContext) {
+    let windowID = aContext.rpId;
+    log("_removeRequestUI for ", windowID);
+    let [chromeWin, browserEl] = this._getUIForWindowID(windowID);
 
-      // callback for the pipe when flow is complete
-      aOptions.onComplete = function pipe_onComplete() {
-        this.cleanUp(aOptions.id);
-      }.bind(this);
-
-      // store context and communicate with pipe
-      this.contexts[aOptions.id] = aOptions;
-      this.contexts[aOptions.id].hostFrame = hostFrame;
-
-      let pipe = new Pipe(aOptions, this);
-      pipe.communicate();
-    }.bind(this));
+    let requestNot = chromeWin.PopupNotifications.getNotification("identity-request", browserEl);
+    if (requestNot)
+      chromeWin.PopupNotifications.remove(requestNot);
   },
 
-  doWatch: function SignInToWebsiteUX_doWatch(aOptions) {
-    aOptions.message = 'identity-delegate-watch';
-    aOptions.showUI = false;
-    this.delegate(aOptions);
-  },
-
-  doRequest: function SignInToWebsiteUX_doRequest(aOptions) {
-    aOptions.message = 'identity-delegate-request';
-    aOptions.showUI = true;
-    this.delegate(aOptions);
-  },
-
-  doLogout: function SignInToWebsiteUX_doLogout(aOptions) {
-    aOptions.message = 'identity-delegate-logout';
-    aOptions.showUI = false;
-    this.delegate(aOptions);
-  }
 };
--- a/dom/identity/DOMIdentity.jsm
+++ b/dom/identity/DOMIdentity.jsm
@@ -9,26 +9,33 @@ const {classes: Cc, interfaces: Ci, util
 // This is the parent process corresponding to nsDOMIdentity.
 this.EXPORTED_SYMBOLS = ["DOMIdentity"];
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/identity/IdentityUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "IdentityService",
+#ifdef MOZ_B2G_VERSION
                                   "resource://gre/modules/identity/MinimalIdentity.jsm");
+#else
+                                  "resource://gre/modules/identity/Identity.jsm");
+#endif
+
+XPCOMUtils.defineLazyModuleGetter(this,
+                                  "Logger",
+                                  "resource://gre/modules/identity/LogUtils.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
                                    "@mozilla.org/parentprocessmessagemanager;1",
                                    "nsIMessageListenerManager");
 
-XPCOMUtils.defineLazyGetter(this, "logger", function() {
-  Cu.import('resource://gre/modules/identity/LogUtils.jsm');
-  return getLogger("Identity", "toolkit.identity.debug");
-});
+function log(...aMessageArgs) {
+  Logger.log.apply(Logger, ["DOMIdentity"].concat(aMessageArgs));
+}
 
 function IDDOMMessage(aOptions) {
   objectCopy(aOptions, this);
 }
 
 function IDPProvisioningContext(aID, aOrigin, aTargetMM) {
   this._id = aID;
   this._origin = aOrigin;
@@ -43,24 +50,24 @@ IDPProvisioningContext.prototype = {
     let message = new IDDOMMessage({id: this.id});
     message.identity = aID;
     message.certDuration = aCertDuration;
     this._mm.sendAsyncMessage("Identity:IDP:CallBeginProvisioningCallback",
                               message);
   },
 
   doGenKeyPairCallback: function IDPPC_doGenKeyPairCallback(aPublicKey) {
-    logger.log("doGenKeyPairCallback");
+    log("doGenKeyPairCallback");
     let message = new IDDOMMessage({id: this.id});
     message.publicKey = aPublicKey;
     this._mm.sendAsyncMessage("Identity:IDP:CallGenKeyPairCallback", message);
   },
 
   doError: function(msg) {
-    logger.warning(msg);
+    log("Provisioning ERROR: " + msg);
   }
 };
 
 function IDPAuthenticationContext(aID, aOrigin, aTargetMM) {
   this._id = aID;
   this._origin = aOrigin;
   this._mm = aTargetMM;
 }
@@ -72,63 +79,61 @@ IDPAuthenticationContext.prototype = {
   doBeginAuthenticationCallback: function IDPAC_doBeginAuthCB(aIdentity) {
     let message = new IDDOMMessage({id: this.id});
     message.identity = aIdentity;
     this._mm.sendAsyncMessage("Identity:IDP:CallBeginAuthenticationCallback",
                               message);
   },
 
   doError: function IDPAC_doError(msg) {
-    logger.warning(msg);
+    log("Authentication ERROR: " + msg);
   }
 };
 
 function RPWatchContext(aOptions, aTargetMM) {
   objectCopy(aOptions, this);
 
   // id and origin are required
   if (! (this.id && this.origin)) {
-    let err = "id and origin are required for RP watch context";
-    logger.error(err);
-    throw new Error(err);
+    throw new Error("id and origin are required for RP watch context");
   }
 
   // default for no loggedInUser is undefined, not null
   this.loggedInUser = aOptions.loggedInUser;
 
   // Maybe internal
   this._internal = aOptions._internal;
 
   this._mm = aTargetMM;
 }
 
 RPWatchContext.prototype = {
   doLogin: function RPWatchContext_onlogin(aAssertion, aMaybeInternalParams) {
-    logger.log("login id: " + this.id);
+    log("doLogin: " + this.id);
     let message = new IDDOMMessage({id: this.id, assertion: aAssertion});
     if (aMaybeInternalParams) {
       message._internalParams = aMaybeInternalParams;
     }
     this._mm.sendAsyncMessage("Identity:RP:Watch:OnLogin", message);
   },
 
   doLogout: function RPWatchContext_onlogout() {
-    logger.log("logout id: " + this.id);
+    log("doLogout: " + this.id);
     let message = new IDDOMMessage({id: this.id});
     this._mm.sendAsyncMessage("Identity:RP:Watch:OnLogout", message);
   },
 
   doReady: function RPWatchContext_onready() {
-    logger.log("ready id: " + this.id);
+    log("doReady: " + this.id);
     let message = new IDDOMMessage({id: this.id});
     this._mm.sendAsyncMessage("Identity:RP:Watch:OnReady", message);
   },
 
   doCancel: function RPWatchContext_oncancel() {
-    logger.log("cancel id: " + this.id);
+    log("doCancel: " + this.id);
     let message = new IDDOMMessage({id: this.id});
     this._mm.sendAsyncMessage("Identity:RP:Watch:OnCancel", message);
   },
 
   doError: function RPWatchContext_onerror(aMessage) {
     log("doError: " + aMessage);
   }
 };
@@ -137,18 +142,16 @@ this.DOMIdentity = {
   // nsIMessageListener
   receiveMessage: function DOMIdentity_receiveMessage(aMessage) {
     let msg = aMessage.json;
 
     // Target is the frame message manager that called us and is
     // used to send replies back to the proper window.
     let targetMM = aMessage.target;
 
-    logger.log("received:", aMessage.name);
-
     switch (aMessage.name) {
       // RP
       case "Identity:RP:Watch":
         this._watch(msg, targetMM);
         break;
       case "Identity:RP:Unwatch":
         this._unwatch(msg, targetMM);
         break;
@@ -209,17 +212,16 @@ this.DOMIdentity = {
              "Identity:RP:Unwatch",
              "child-process-shutdown"],
 
   // Private.
   _init: function DOMIdentity__init() {
     Services.ww.registerNotification(this);
     Services.obs.addObserver(this, "xpcom-shutdown", false);
     this._subscribeListeners();
-    logger.log("DOM identity service initialized");
   },
 
   _subscribeListeners: function DOMIdentity__subscribeListeners() {
     if (!ppmm) return;
     for (let message of this.messages) {
       ppmm.addMessageListener(message, this);
     }
   },
@@ -227,28 +229,26 @@ this.DOMIdentity = {
   _unsubscribeListeners: function DOMIdentity__unsubscribeListeners() {
     for (let message of this.messages) {
       ppmm.removeMessageListener(message, this);
     }
     ppmm = null;
   },
 
   _resetFrameState: function(aContext) {
-    logger.log("_resetFrameState: ", aContext.id);
+    log("_resetFrameState: ", aContext.id);
     if (!aContext._mm) {
-      let err = "Trying to reset an invalid context";
-      logger.error(err);
-      throw new Error(err);
+      throw new Error("ERROR: Trying to reset an invalid context");
     }
     let message = new IDDOMMessage({id: aContext.id});
     aContext._mm.sendAsyncMessage("Identity:ResetState", message);
   },
 
   _watch: function DOMIdentity__watch(message, targetMM) {
-    logger.log("DOMIdentity__watch: " + message.id);
+    log("DOMIdentity__watch: " + message.id);
     // Pass an object with the watch members to Identity.jsm so it can call the
     // callbacks.
     let context = new RPWatchContext(message, targetMM);
     IdentityService.RP.watch(context);
   },
 
   _unwatch: function DOMIdentity_unwatch(message, targetMM) {
     IdentityService.RP.unwatch(message.id, targetMM);
--- a/dom/identity/nsDOMIdentity.js
+++ b/dom/identity/nsDOMIdentity.js
@@ -18,28 +18,22 @@ const PREF_SYNTHETIC_EVENTS_OK = "dom.id
 const MAX_STRING_LENGTH = 2048;
 // Maximum number of times navigator.id.request can be called for a document
 const MAX_RP_CALLS = 100;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/identity/IdentityUtils.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "logger", function() {
-  Cu.import('resource://gre/modules/identity/LogUtils.jsm');
-  return getLogger("Identity", "toolkit.identity.debug");
-});
-
 // This is the child process corresponding to nsIDOMIdentity
 XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
                                    "@mozilla.org/childprocessmessagemanager;1",
                                    "nsIMessageSender");
 
 function nsDOMIdentity(aIdentityInternal) {
-  logger.log("nsDOMIdentity constructor");
   this._identityInternal = aIdentityInternal;
 }
 nsDOMIdentity.prototype = {
   __exposedProps__: {
     // Relying Party (RP)
     watch: 'r',
     request: 'r',
     logout: 'r',
@@ -66,17 +60,16 @@ nsDOMIdentity.prototype = {
     return true;
   },
 
   /**
    * Relying Party (RP) APIs
    */
 
   watch: function nsDOMIdentity_watch(aOptions) {
-    logger.log(aOptions);
     if (this._rpWatcher) {
       throw new Error("navigator.id.watch was already called");
     }
 
     if (!aOptions || typeof(aOptions) !== "object") {
       throw new Error("options argument to watch is required");
     }
 
@@ -91,59 +84,56 @@ nsDOMIdentity.prototype = {
 
     // Optional callback "onready"
     if (aOptions["onready"]
         && typeof(aOptions['onready']) !== "function") {
       throw new Error("onready must be a function");
     }
 
     let message = this.DOMIdentityMessage(aOptions);
-    logger.log(message);
 
     // loggedInUser vs loggedInEmail
     // https://developer.mozilla.org/en-US/docs/DOM/navigator.id.watch
     // This parameter, loggedInUser, was renamed from loggedInEmail in early
     // September, 2012. Both names will continue to work for the time being,
     // but code should be changed to use loggedInUser instead.
     checkRenamed(aOptions, "loggedInEmail", "loggedInUser");
     message["loggedInUser"] = aOptions["loggedInUser"];
 
-    logger.log(message);
     let emailType = typeof(aOptions["loggedInUser"]);
     if (aOptions["loggedInUser"] && aOptions["loggedInUser"] !== "undefined") {
       if (emailType !== "string") {
         throw new Error("loggedInUser must be a String or null");
       }
 
       // TODO: Bug 767610 - check email format.
       // See nsHTMLInputElement::IsValidEmailAddress
       if (aOptions["loggedInUser"].indexOf("@") == -1
           || aOptions["loggedInUser"].length > MAX_STRING_LENGTH) {
         throw new Error("loggedInUser is not valid");
       }
       // Set loggedInUser in this block that "undefined" doesn't get through.
       message.loggedInUser = aOptions.loggedInUser;
     }
-    logger.log("loggedInUser:", message.loggedInUser);
+    this._log("loggedInUser: " + message.loggedInUser);
 
     this._rpWatcher = aOptions;
     this._identityInternal._mm.sendAsyncMessage("Identity:RP:Watch", message);
   },
 
   request: function nsDOMIdentity_request(aOptions) {
-    logger.log(aOptions);
     let util = this._window.QueryInterface(Ci.nsIInterfaceRequestor)
                            .getInterface(Ci.nsIDOMWindowUtils);
 
     // The only time we permit calling of request() outside of a user
     // input handler is when we are handling the (deprecated) get() or
     // getVerifiedEmail() calls, which make use of an RP context
     // marked as _internal.
     if (this.nativeEventsRequired && !util.isHandlingUserInput && !aOptions._internal) {
-      error("request: rejecting non-native event");
+      this._log("request: rejecting non-native event");
       return;
     }
 
     // Has the caller called watch() before this?
     if (!this._rpWatcher) {
       throw new Error("navigator.id.request called before navigator.id.watch");
     }
     if (this._rpCalls > MAX_RP_CALLS) {
@@ -176,17 +166,16 @@ nsDOMIdentity.prototype = {
       }
     }
 
     this._rpCalls++;
     this._identityInternal._mm.sendAsyncMessage("Identity:RP:Request", message);
   },
 
   logout: function nsDOMIdentity_logout() {
-    logger.log("logout");
     if (!this._rpWatcher) {
       throw new Error("navigator.id.logout called before navigator.id.watch");
     }
     if (this._rpCalls > MAX_RP_CALLS) {
       throw new Error("navigator.id.logout called too many times");
     }
 
     this._rpCalls++;
@@ -249,72 +238,72 @@ nsDOMIdentity.prototype = {
       onlogout: function get_onlogout() {},
       onready: function get_onready() {
         self.request(opts);
       }
     });
   },
 
   getVerifiedEmail: function nsDOMIdentity_getVerifiedEmail(aCallback) {
-    error("WARNING: getVerifiedEmail has been deprecated");
+    Cu.reportError("WARNING: getVerifiedEmail has been deprecated");
     this.get(aCallback, {});
   },
 
   /**
    *  Identity Provider (IDP) Provisioning APIs
    */
 
   beginProvisioning: function nsDOMIdentity_beginProvisioning(aCallback) {
-    logger.log("beginProvisioning");
+    this._log("beginProvisioning");
     if (this._beginProvisioningCallback) {
       throw new Error("navigator.id.beginProvisioning already called.");
     }
     if (!aCallback || typeof(aCallback) !== "function") {
       throw new Error("beginProvisioning callback is required.");
     }
 
     this._beginProvisioningCallback = aCallback;
     this._identityInternal._mm.sendAsyncMessage("Identity:IDP:BeginProvisioning",
                                                 this.DOMIdentityMessage());
   },
 
   genKeyPair: function nsDOMIdentity_genKeyPair(aCallback) {
-    logger.log("genKeyPair");
+    this._log("genKeyPair");
     if (!this._beginProvisioningCallback) {
       throw new Error("navigator.id.genKeyPair called outside of provisioning");
     }
     if (this._genKeyPairCallback) {
       throw new Error("navigator.id.genKeyPair already called.");
     }
     if (!aCallback || typeof(aCallback) !== "function") {
       throw new Error("genKeyPair callback is required.");
     }
 
     this._genKeyPairCallback = aCallback;
     this._identityInternal._mm.sendAsyncMessage("Identity:IDP:GenKeyPair",
                                                 this.DOMIdentityMessage());
   },
 
   registerCertificate: function nsDOMIdentity_registerCertificate(aCertificate) {
-    logger.log("registerCertificate");
+    this._log("registerCertificate");
     if (!this._genKeyPairCallback) {
       throw new Error("navigator.id.registerCertificate called outside of provisioning");
     }
     if (this._provisioningEnded) {
       throw new Error("Provisioning already ended");
     }
     this._provisioningEnded = true;
 
     let message = this.DOMIdentityMessage();
     message.cert = aCertificate;
     this._identityInternal._mm.sendAsyncMessage("Identity:IDP:RegisterCertificate", message);
   },
 
   raiseProvisioningFailure: function nsDOMIdentity_raiseProvisioningFailure(aReason) {
-    logger.log("raiseProvisioningFailure '" + aReason + "'");
+    this._log("raiseProvisioningFailure '" + aReason + "'");
     if (this._provisioningEnded) {
       throw new Error("Provisioning already ended");
     }
     if (!aReason || typeof(aReason) != "string") {
       throw new Error("raiseProvisioningFailure reason is required");
     }
     this._provisioningEnded = true;
 
@@ -323,17 +312,17 @@ nsDOMIdentity.prototype = {
     this._identityInternal._mm.sendAsyncMessage("Identity:IDP:ProvisioningFailure", message);
   },
 
   /**
    *  Identity Provider (IDP) Authentication APIs
    */
 
   beginAuthentication: function nsDOMIdentity_beginAuthentication(aCallback) {
-    logger.log("beginAuthentication");
+    this._log("beginAuthentication");
     if (this._beginAuthenticationCallback) {
       throw new Error("navigator.id.beginAuthentication already called.");
     }
     if (typeof(aCallback) !== "function") {
       throw new Error("beginAuthentication callback is required.");
     }
     if (!aCallback || typeof(aCallback) !== "function") {
       throw new Error("beginAuthentication callback is required.");
@@ -411,54 +400,54 @@ nsDOMIdentity.prototype = {
           return;
         }
         this._initializeState();
         Services.obs.notifyObservers(null, "identity-DOM-state-reset", this._id);
         break;
       case "Identity:RP:Watch:OnLogin":
         // Do we have a watcher?
         if (!this._rpWatcher) {
-          logger.warning("Received OnLogin message, but there is no RP watcher");
+          this._log("WARNING: Received OnLogin message, but there is no RP watcher");
           return;
         }
 
         if (this._rpWatcher.onlogin) {
           if (this._rpWatcher._internal) {
             this._rpWatcher.onlogin(msg.assertion, msg._internalParams);
           } else {
             this._rpWatcher.onlogin(msg.assertion);
           }
         }
         break;
       case "Identity:RP:Watch:OnLogout":
         // Do we have a watcher?
         if (!this._rpWatcher) {
-          logger.warning("Received OnLogout message, but there is no RP watcher");
+          this._log("WARNING: Received OnLogout message, but there is no RP watcher");
           return;
         }
 
         if (this._rpWatcher.onlogout) {
           this._rpWatcher.onlogout();
         }
         break;
       case "Identity:RP:Watch:OnReady":
         // Do we have a watcher?
         if (!this._rpWatcher) {
-          logger.warning("Received OnReady message, but there is no RP watcher");
+          this._log("WARNING: Received OnReady message, but there is no RP watcher");
           return;
         }
 
         if (this._rpWatcher.onready) {
           this._rpWatcher.onready();
         }
         break;
       case "Identity:RP:Watch:OnCancel":
         // Do we have a watcher?
         if (!this._rpWatcher) {
-          logger.warning("Received OnCancel message, but there is no RP watcher");
+          this._log("WARNING: Received OnCancel message, but there is no RP watcher");
           return;
         }
 
         if (this._onCancelRequestCallback) {
           this._onCancelRequestCallback();
         }
         break;
       case "Identity:IDP:CallBeginProvisioningCallback":
@@ -468,16 +457,20 @@ nsDOMIdentity.prototype = {
         this._callGenKeyPairCallback(msg);
         break;
       case "Identity:IDP:CallBeginAuthenticationCallback":
         this._callBeginAuthenticationCallback(msg);
         break;
     }
   },
 
+  _log: function nsDOMIdentity__log(msg) {
+    this._identityInternal._log(msg);
+  },
+
   _callGenKeyPairCallback: function nsDOMIdentity__callGenKeyPairCallback(message) {
     // create a pubkey object that works
     let chrome_pubkey = JSON.parse(message.publicKey);
 
     // bunch of stuff to create a proper object in window context
     function genPropDesc(value) {
       return {
         enumerable: true, configurable: true, writable: true, value: value
@@ -527,17 +520,17 @@ nsDOMIdentity.prototype = {
 
     // window origin
     message.origin = this._origin;
 
     return message;
   },
 
   uninit: function DOMIdentity_uninit() {
-    logger.log("unwatch", this._id);
+    this._log("nsDOMIdentity uninit()");
     this._identityInternal._mm.sendAsyncMessage(
       "Identity:RP:Unwatch",
       { id: this._id }
     );
   }
 
 };
 
@@ -600,17 +593,17 @@ nsDOMIdentityInternal.prototype = {
 
     this._identity._init(aWindow);
 
     let util = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
                       .getInterface(Ci.nsIDOMWindowUtils);
     this._id = util.outerWindowID;
     this._innerWindowID = util.currentInnerWindowID;
 
-    logger.log("init was called from", aWindow.document.location);
+    this._log("init was called from " + aWindow.document.location);
 
     this._mm = cpmm;
 
     // Setup listeners for messages from parent process.
     this._messages = [
       "Identity:ResetState",
       "Identity:RP:Watch:OnLogin",
       "Identity:RP:Watch:OnLogout",
@@ -625,16 +618,24 @@ nsDOMIdentityInternal.prototype = {
     }, this);
 
     // Setup observers so we can remove message listeners.
     Services.obs.addObserver(this, "inner-window-destroyed", false);
 
     return this._identity;
   },
 
+  // Private.
+  _log: function nsDOMIdentityInternal__log(msg) {
+    if (!this._debug) {
+      return;
+    }
+    dump("nsDOMIdentity (" + this._id + "): " + msg + "\n");
+  },
+
   // Component setup.
   classID: Components.ID("{210853d9-2c97-4669-9761-b1ab9cbf57ef}"),
 
   QueryInterface: XPCOMUtils.generateQI(
     [Ci.nsIDOMGlobalPropertyInitializer, Ci.nsIMessageListener]
   ),
 
   classInfo: XPCOMUtils.generateCI({
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -379,17 +379,17 @@ pref("toolkit.telemetry.server", "https:
 pref("toolkit.telemetry.server_owner", "Mozilla");
 // Information page about telemetry (temporary ; will be about:telemetry in the end)
 pref("toolkit.telemetry.infoURL", "http://www.mozilla.com/legal/privacy/firefox.html#telemetry");
 // Determines whether full SQL strings are returned when they might contain sensitive info
 // i.e. dynamically constructed SQL strings or SQL executed by addons against addon DBs
 pref("toolkit.telemetry.debugSlowSql", false);
 
 // Identity module
-pref("dom.identity.enabled", false);
+pref("toolkit.identity.enabled", false);
 pref("toolkit.identity.debug", false);
 
 // Enable deprecation warnings.
 pref("devtools.errorconsole.deprecation_warnings", true);
 
 // Disable remote debugging protocol logging
 pref("devtools.debugger.log", false);
 // Disable remote debugging connections
--- a/toolkit/identity/Identity.jsm
+++ b/toolkit/identity/Identity.jsm
@@ -10,28 +10,31 @@ this.EXPORTED_SYMBOLS = ["IdentityServic
 
 const Cu = Components.utils;
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/identity/LogUtils.jsm");
 Cu.import("resource://gre/modules/identity/IdentityStore.jsm");
 Cu.import("resource://gre/modules/identity/RelyingParty.jsm");
 Cu.import("resource://gre/modules/identity/IdentityProvider.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this,
                                   "jwcrypto",
                                   "resource://gre/modules/identity/jwcrypto.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "logger", function() {
-  Cu.import('resource://gre/modules/identity/LogUtils.jsm');
-  return getLogger("Identity", "toolkit.identity.debug");
-});
+function log(...aMessageArgs) {
+  Logger.log.apply(Logger, ["core"].concat(aMessageArgs));
+}
+function reportError(...aMessageArgs) {
+  Logger.reportError.apply(Logger, ["core"].concat(aMessageArgs));
+}
 
 function IDService() {
   Services.obs.addObserver(this, "quit-application-granted", false);
   Services.obs.addObserver(this, "identity-auth-complete", false);
 
   this._store = IdentityStore;
   this.RP = RelyingParty;
   this.IDP = IdentityProvider;
@@ -45,17 +48,17 @@ IDService.prototype = {
       case "quit-application-granted":
         Services.obs.removeObserver(this, "quit-application-granted");
         this.shutdown();
         break;
       case "identity-auth-complete":
         if (!aSubject || !aSubject.wrappedJSObject)
           break;
         let subject = aSubject.wrappedJSObject;
-        logger.log("Auth complete:", aSubject.wrappedJSObject);
+        log("Auth complete:", aSubject.wrappedJSObject);
         // We have authenticated in order to provision an identity.
         // So try again.
         this.selectIdentity(subject.rpId, subject.identity);
         break;
     }
   },
 
   reset: function reset() {
@@ -65,17 +68,17 @@ IDService.prototype = {
     // called here, on RP, on IDP, and on the store.  So you don't
     // need to use this :)
     this._store.reset();
     this.RP.reset();
     this.IDP.reset();
   },
 
   shutdown: function shutdown() {
-    logger.log("shutdown");
+    log("shutdown");
     Services.obs.removeObserver(this, "identity-auth-complete");
     Services.obs.removeObserver(this, "quit-application-granted");
   },
 
   /**
    * Parse an email into username and domain if it is valid, else return null
    */
   parseEmail: function parseEmail(email) {
@@ -109,34 +112,34 @@ IDService.prototype = {
    * @param aRPId
    *        (integer) the id of the doc object obtained in .watch() and
    *                  passed to the UX component.
    *
    * @param aIdentity
    *        (string) the email chosen for login
    */
   selectIdentity: function selectIdentity(aRPId, aIdentity) {
-    logger.log("selectIdentity: RP id:", aRPId, "identity:", aIdentity);
+    log("selectIdentity: RP id:", aRPId, "identity:", aIdentity);
 
     // Get the RP that was stored when watch() was invoked.
     let rp = this.RP._rpFlows[aRPId];
     if (!rp) {
-      logger.warning("selectIdentity", "Invalid RP id: ", aRPId);
+      reportError("selectIdentity", "Invalid RP id: ", aRPId);
       return;
     }
 
     // It's possible that we are in the process of provisioning an
     // identity.
     let provId = rp.provId;
 
     let rpLoginOptions = {
       loggedInUser: aIdentity,
       origin: rp.origin
     };
-    logger.log("selectIdentity: provId:", provId, "origin:", rp.origin);
+    log("selectIdentity: provId:", provId, "origin:", rp.origin);
 
     // Once we have a cert, and once the user is authenticated with the
     // IdP, we can generate an assertion and deliver it to the doc.
     let self = this;
     this.RP._generateAssertion(rp.origin, aIdentity, function hadReadyAssertion(err, assertion) {
       if (!err && assertion) {
         self.RP._doLogin(rp, rpLoginOptions, assertion);
         return;
@@ -167,17 +170,17 @@ IDService.prototype = {
             // We are not authenticated.  If we have already tried to
             // authenticate and failed, then this is a "hard fail" and
             // we give up.  Otherwise we try to authenticate with the
             // IdP.
 
             if (self.IDP._provisionFlows[aProvId].didAuthentication) {
               self.IDP._cleanUpProvisionFlow(aProvId);
               self.RP._cleanUpProvisionFlow(aRPId, aProvId);
-              logger.error("ERROR: selectIdentity: authentication hard fail");
+              log("ERROR: selectIdentity: authentication hard fail");
               rp.doError("Authentication fail.");
               return;
             }
             // Try to authenticate with the IdP.  Note that we do
             // not clean up the provision flow here.  We will continue
             // to use it.
             self.IDP._doAuthentication(aProvId, idpParams);
             return;
@@ -214,17 +217,17 @@ IDService.prototype = {
    */
   _discoverIdentityProvider: function _discoverIdentityProvider(aIdentity, aCallback) {
     // XXX bug 767610 - validate email address call
     // When that is available, we can remove this custom parser
     var parsedEmail = this.parseEmail(aIdentity);
     if (parsedEmail === null) {
       return aCallback("Could not parse email: " + aIdentity);
     }
-    logger.log("_discoverIdentityProvider: identity:", aIdentity, "domain:", parsedEmail.domain);
+    log("_discoverIdentityProvider: identity:", aIdentity, "domain:", parsedEmail.domain);
 
     this._fetchWellKnownFile(parsedEmail.domain, function fetchedWellKnown(err, idpParams) {
       // idpParams includes the pk, authorization url, and
       // provisioning url.
 
       // XXX bug 769861 follow any authority delegations
       // if no well-known at any point in the delegation
       // fall back to browserid.org as IdP
@@ -243,60 +246,60 @@ IDService.prototype = {
    *                 https.
    *
    * @param aCallback
    *
    */
   _fetchWellKnownFile: function _fetchWellKnownFile(aDomain, aCallback, aScheme='https') {
     // XXX bug 769854 make tests https and remove aScheme option
     let url = aScheme + '://' + aDomain + "/.well-known/browserid";
-    logger.log("_fetchWellKnownFile:", url);
+    log("_fetchWellKnownFile:", url);
 
     // this appears to be a more successful way to get at xmlhttprequest (which supposedly will close with a window
     let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
                 .createInstance(Ci.nsIXMLHttpRequest);
 
     // XXX bug 769865 gracefully handle being off-line
     // XXX bug 769866 decide on how to handle redirects
     req.open("GET", url, true);
     req.responseType = "json";
     req.mozBackgroundRequest = true;
     req.onload = function _fetchWellKnownFile_onload() {
       if (req.status < 200 || req.status >= 400) {
-        logger.log("_fetchWellKnownFile", url, ": server returned status:", req.status);
+        log("_fetchWellKnownFile", url, ": server returned status:", req.status);
         return aCallback("Error");
       }
       try {
         let idpParams = req.response;
 
         // Verify that the IdP returned a valid configuration
         if (! (idpParams.provisioning &&
             idpParams.authentication &&
             idpParams['public-key'])) {
           let errStr= "Invalid well-known file from: " + aDomain;
-          logger.log("_fetchWellKnownFile:", errStr);
+          log("_fetchWellKnownFile:", errStr);
           return aCallback(errStr);
         }
 
         let callbackObj = {
           domain: aDomain,
           idpParams: idpParams,
         };
-        logger.log("_fetchWellKnownFile result: ", callbackObj);
+        log("_fetchWellKnownFile result: ", callbackObj);
         // Yay.  Valid IdP configuration for the domain.
         return aCallback(null, callbackObj);
 
       } catch (err) {
-        logger.warning("_fetchWellKnownFile", "Bad configuration from", aDomain, err);
+        reportError("_fetchWellKnownFile", "Bad configuration from", aDomain, err);
         return aCallback(err.toString());
       }
     };
     req.onerror = function _fetchWellKnownFile_onerror() {
-      logger.log("_fetchWellKnownFile", "ERROR:", req.status, req.statusText);
-      logger.error("ERROR: _fetchWellKnownFile:", err);
+      log("_fetchWellKnownFile", "ERROR:", req.status, req.statusText);
+      log("ERROR: _fetchWellKnownFile:", err);
       return aCallback("Error");
     };
     req.send(null);
   },
 
 };
 
 this.IdentityService = new IDService();
--- a/toolkit/identity/IdentityProvider.jsm
+++ b/toolkit/identity/IdentityProvider.jsm
@@ -8,29 +8,33 @@
 
 const Cu = Components.utils;
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/identity/LogUtils.jsm");
 Cu.import("resource://gre/modules/identity/Sandbox.jsm");
 
 this.EXPORTED_SYMBOLS = ["IdentityProvider"];
 const FALLBACK_PROVIDER = "browserid.org";
 
 XPCOMUtils.defineLazyModuleGetter(this,
                                   "jwcrypto",
                                   "resource://gre/modules/identity/jwcrypto.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "logger", function() {
-  Cu.import('resource://gre/modules/identity/LogUtils.jsm');
-  return getLogger("Identity IDP", "toolkit.identity.debug");
-});
+function log(...aMessageArgs) {
+  Logger.log.apply(Logger, ["IDP"].concat(aMessageArgs));
+}
+function reportError(...aMessageArgs) {
+  Logger.reportError.apply(Logger, ["IDP"].concat(aMessageArgs));
+}
+
 
 function IdentityProviderService() {
   XPCOMUtils.defineLazyModuleGetter(this,
                                     "_store",
                                     "resource://gre/modules/identity/IdentityStore.jsm",
                                     "IdentityStore");
 
   this.reset();
@@ -67,17 +71,17 @@ IdentityProviderService.prototype = {
 
   getProvisionFlow: function getProvisionFlow(aProvId, aErrBack) {
     let provFlow = this._provisionFlows[aProvId];
     if (provFlow) {
       return provFlow;
     }
 
     let err = "No provisioning flow found with id " + aProvId;
-    logger.warning("ERROR:", err);
+    log("ERROR:", err);
     if (typeof aErrBack === 'function') {
       aErrBack(err);
     }
   },
 
   shutdown: function RP_shutdown() {
     this.reset();
 
@@ -113,25 +117,25 @@ IdentityProviderService.prototype = {
    *
    * @param aCallback
    *        (function) callback to invoke on completion
    *                   with first-positional parameter the error.
    */
   _provisionIdentity: function _provisionIdentity(aIdentity, aIDPParams, aProvId, aCallback) {
     let provPath = aIDPParams.idpParams.provisioning;
     let url = Services.io.newURI("https://" + aIDPParams.domain, null, null).resolve(provPath);
-    logger.log("_provisionIdentity: identity:", aIdentity, "url:", url);
+    log("_provisionIdentity: identity:", aIdentity, "url:", url);
 
     // If aProvId is not null, then we already have a flow
     // with a sandbox.  Otherwise, get a sandbox and create a
     // new provision flow.
 
     if (aProvId) {
       // Re-use an existing sandbox
-      logger.log("_provisionIdentity: re-using sandbox in provisioning flow with id:", aProvId);
+      log("_provisionIdentity: re-using sandbox in provisioning flow with id:", aProvId);
       this._provisionFlows[aProvId].provisioningSandbox.reload();
 
     } else {
       this._createProvisioningSandbox(url, function createdSandbox(aSandbox) {
         // create a provisioning flow, using the sandbox id, and
         // stash callback associated with this provisioning workflow.
 
         let provId = aSandbox.id;
@@ -140,17 +144,17 @@ IdentityProviderService.prototype = {
           idpParams: aIDPParams,
           securityLevel: this.securityLevel,
           provisioningSandbox: aSandbox,
           callback: function doCallback(aErr) {
             aCallback(aErr, provId);
           },
         };
 
-        logger.log("_provisionIdentity: Created sandbox and provisioning flow with id:", provId);
+        log("_provisionIdentity: Created sandbox and provisioning flow with id:", provId);
         // XXX bug 769862 - provisioning flow should timeout after N seconds
 
       }.bind(this));
     }
   },
 
   // DOM Methods
   /**
@@ -158,17 +162,17 @@ IdentityProviderService.prototype = {
    *
    * @param aCaller
    *        (object)  the iframe sandbox caller with all callbacks and
    *                  other information.  Callbacks include:
    *                  - doBeginProvisioningCallback(id, duration_s)
    *                  - doGenKeyPairCallback(pk)
    */
   beginProvisioning: function beginProvisioning(aCaller) {
-    logger.log("beginProvisioning:", aCaller.id);
+    log("beginProvisioning:", aCaller.id);
 
     // Expect a flow for this caller already to be underway.
     let provFlow = this.getProvisionFlow(aCaller.id, aCaller.doError);
 
     // keep the caller object around
     provFlow.caller = aCaller;
 
     let identity = provFlow.identity;
@@ -190,17 +194,17 @@ IdentityProviderService.prototype = {
    * the provisioning iframe sandbox has called
    * navigator.id.raiseProvisioningFailure()
    *
    * @param aProvId
    *        (int)  the identifier of the provisioning flow tied to that sandbox
    * @param aReason
    */
   raiseProvisioningFailure: function raiseProvisioningFailure(aProvId, aReason) {
-    logger.warning("Provisioning failure", aReason);
+    reportError("Provisioning failure", aReason);
 
     // look up the provisioning caller and its callback
     let provFlow = this.getProvisionFlow(aProvId);
 
     // Sandbox is deleted in _cleanUpProvisionFlow in case we re-use it.
 
     // This may be either a "soft" or "hard" fail.  If it's a
     // soft fail, we'll flow through setAuthenticationFlow, where
@@ -223,35 +227,35 @@ IdentityProviderService.prototype = {
    * the beginProvisioning() call first.
    */
   genKeyPair: function genKeyPair(aProvId) {
     // Look up the provisioning caller and make sure it's valid.
     let provFlow = this.getProvisionFlow(aProvId);
 
     if (!provFlow.didBeginProvisioning) {
       let errStr = "ERROR: genKeyPair called before beginProvisioning";
-      logger.warning(errStr);
+      log(errStr);
       provFlow.callback(errStr);
       return;
     }
 
     // Ok generate a keypair
     jwcrypto.generateKeyPair(jwcrypto.ALGORITHMS.DS160, function gkpCb(err, kp) {
-      logger.log("in gkp callback");
+      log("in gkp callback");
       if (err) {
-        logger.error("ERROR: genKeyPair:", err);
+        log("ERROR: genKeyPair:", err);
         provFlow.callback(err);
         return;
       }
 
       provFlow.kp = kp;
 
       // Serialize the publicKey of the keypair and send it back to the
       // sandbox.
-      logger.log("genKeyPair: generated keypair for provisioning flow with id:", aProvId);
+      log("genKeyPair: generated keypair for provisioning flow with id:", aProvId);
       provFlow.caller.doGenKeyPairCallback(provFlow.kp.serializedPublicKey);
     }.bind(this));
   },
 
   /**
    * When navigator.id.registerCertificate is called from provisioning iframe
    * sandbox.
    *
@@ -262,28 +266,28 @@ IdentityProviderService.prototype = {
    *        (integer) the identifier of the provisioning caller tied to that
    *                  sandbox
    *
    * @param aCert
    *        (String)  A JWT representing the signed certificate for the user
    *                  being provisioned, provided by the IdP.
    */
   registerCertificate: function registerCertificate(aProvId, aCert) {
-    logger.log("registerCertificate:", aProvId, aCert);
+    log("registerCertificate:", aProvId, aCert);
 
     // look up provisioning caller, make sure it's valid.
     let provFlow = this.getProvisionFlow(aProvId);
 
     if (!provFlow.caller) {
-      logger.warning("registerCertificate", "No provision flow or caller");
+      reportError("registerCertificate", "No provision flow or caller");
       return;
     }
     if (!provFlow.kp)  {
       let errStr = "Cannot register a certificate without a keypair";
-      logger.warning("registerCertificate", errStr);
+      reportError("registerCertificate", errStr);
       provFlow.callback(errStr);
       return;
     }
 
     // store the keypair and certificate just provided in IDStore.
     this._store.addIdentity(provFlow.identity, provFlow.kp, aCert);
 
     // Great success!
@@ -299,17 +303,17 @@ IdentityProviderService.prototype = {
    * @param aProvId
    *        (int) the identifier of the provisioning flow which failed
    *
    * @param aCallback
    *        (function) to invoke upon completion, with
    *                   first-positional-param error.
    */
   _doAuthentication: function _doAuthentication(aProvId, aIDPParams) {
-    logger.log("_doAuthentication: provId:", aProvId, "idpParams:", aIDPParams);
+    log("_doAuthentication: provId:", aProvId, "idpParams:", aIDPParams);
     // create an authentication caller and its identifier AuthId
     // stash aIdentity, idpparams, and callback in it.
 
     // extract authentication URL from idpParams
     let authPath = aIDPParams.idpParams.authentication;
     let authURI = Services.io.newURI("https://" + aIDPParams.domain, null, null).resolve(authPath);
 
     // beginAuthenticationFlow causes the "identity-auth" topic to be
@@ -332,49 +336,49 @@ IdentityProviderService.prototype = {
    * aCaller is an expected authentication-flow identifier. If not, we throw
    * an error or something.
    *
    * @param aCaller
    *        (object)  the authentication caller
    *
    */
   beginAuthentication: function beginAuthentication(aCaller) {
-    logger.log("beginAuthentication: caller id:", aCaller.id);
+    log("beginAuthentication: caller id:", aCaller.id);
 
     // Begin the authentication flow after having concluded a provisioning
     // flow.  The aCaller that the DOM gives us will have the same ID as
     // the provisioning flow we just concluded.  (see setAuthenticationFlow)
     let authFlow = this._authenticationFlows[aCaller.id];
     if (!authFlow) {
       return aCaller.doError("beginAuthentication: no flow for caller id", aCaller.id);
     }
 
     authFlow.caller = aCaller;
 
     let identity = this._provisionFlows[authFlow.provId].identity;
 
     // tell the UI to start the authentication process
-    logger.log("beginAuthentication: authFlow:", aCaller.id, "identity:", identity);
+    log("beginAuthentication: authFlow:", aCaller.id, "identity:", identity);
     return authFlow.caller.doBeginAuthenticationCallback(identity);
   },
 
   /**
    * The auth frame has called navigator.id.completeAuthentication
    *
    * @param aAuthId
    *        (int)  the identifier of the authentication caller tied to that sandbox
    *
    */
   completeAuthentication: function completeAuthentication(aAuthId) {
-    logger.log("completeAuthentication:", aAuthId);
+    log("completeAuthentication:", aAuthId);
 
     // look up the AuthId caller, and get its callback.
     let authFlow = this._authenticationFlows[aAuthId];
     if (!authFlow) {
-      logger.warning("completeAuthentication", "No auth flow with id", aAuthId);
+      reportError("completeAuthentication", "No auth flow with id", aAuthId);
       return;
     }
     let provId = authFlow.provId;
 
     // delete caller
     delete authFlow['caller'];
     delete this._authenticationFlows[aAuthId];
 
@@ -390,92 +394,92 @@ IdentityProviderService.prototype = {
   /**
    * The auth frame has called navigator.id.cancelAuthentication
    *
    * @param aAuthId
    *        (int)  the identifier of the authentication caller
    *
    */
   cancelAuthentication: function cancelAuthentication(aAuthId) {
-    logger.log("cancelAuthentication:", aAuthId);
+    log("cancelAuthentication:", aAuthId);
 
     // look up the AuthId caller, and get its callback.
     let authFlow = this._authenticationFlows[aAuthId];
     if (!authFlow) {
-      logger.warning("cancelAuthentication", "No auth flow with id:", aAuthId);
+      reportError("cancelAuthentication", "No auth flow with id:", aAuthId);
       return;
     }
     let provId = authFlow.provId;
 
     // delete caller
     delete authFlow['caller'];
     delete this._authenticationFlows[aAuthId];
 
     let provFlow = this.getProvisionFlow(provId);
     provFlow.didAuthentication = true;
     Services.obs.notifyObservers(null, "identity-auth-complete", aAuthId);
 
     // invoke callback with ERROR.
     let errStr = "Authentication canceled by IDP";
-    logger.log("ERROR: cancelAuthentication:", errStr);
+    log("ERROR: cancelAuthentication:", errStr);
     provFlow.callback(errStr);
   },
 
   /**
    * Called by the UI to set the ID and caller for the authentication flow after it gets its ID
    */
   setAuthenticationFlow: function(aAuthId, aProvId) {
     // this is the transition point between the two flows,
     // provision and authenticate.  We tell the auth flow which
     // provisioning flow it is started from.
-    logger.log("setAuthenticationFlow: authId:", aAuthId, "provId:", aProvId);
+    log("setAuthenticationFlow: authId:", aAuthId, "provId:", aProvId);
     this._authenticationFlows[aAuthId] = { provId: aProvId };
     this._provisionFlows[aProvId].authId = aAuthId;
   },
 
   /**
    * Load the provisioning URL in a hidden frame to start the provisioning
    * process.
    */
   _createProvisioningSandbox: function _createProvisioningSandbox(aURL, aCallback) {
-    logger.log("_createProvisioningSandbox:", aURL);
+    log("_createProvisioningSandbox:", aURL);
 
     if (!this._sandboxConfigured) {
       // Configure message manager listening on the hidden window
       Cu.import("resource://gre/modules/DOMIdentity.jsm");
       DOMIdentity._configureMessages(Services.appShell.hiddenDOMWindow, true);
       this._sandboxConfigured = true;
     }
 
     new Sandbox(aURL, aCallback);
   },
 
   /**
    * Load the authentication UI to start the authentication process.
    */
   _beginAuthenticationFlow: function _beginAuthenticationFlow(aProvId, aURL) {
-    logger.log("_beginAuthenticationFlow:", aProvId, aURL);
+    log("_beginAuthenticationFlow:", aProvId, aURL);
     let propBag = {provId: aProvId};
 
     Services.obs.notifyObservers({wrappedJSObject:propBag}, "identity-auth", aURL);
   },
 
   /**
    * Clean up a provision flow and the authentication flow and sandbox
    * that may be attached to it.
    */
   _cleanUpProvisionFlow: function _cleanUpProvisionFlow(aProvId) {
-    logger.log('_cleanUpProvisionFlow:', aProvId);
+    log('_cleanUpProvisionFlow:', aProvId);
     let prov = this._provisionFlows[aProvId];
 
     // Clean up the sandbox, if there is one.
     if (prov.provisioningSandbox) {
       let sandbox = this._provisionFlows[aProvId]['provisioningSandbox'];
       if (sandbox.free) {
-        logger.log('_cleanUpProvisionFlow: freeing sandbox');
+        log('_cleanUpProvisionFlow: freeing sandbox');
         sandbox.free();
       }
       delete this._provisionFlows[aProvId]['provisioningSandbox'];
     }
 
     // Clean up a related authentication flow, if there is one.
     if (this._authenticationFlows[prov.authId]) {
       delete this._authenticationFlows[prov.authId];
--- a/toolkit/identity/IdentityUtils.jsm
+++ b/toolkit/identity/IdentityUtils.jsm
@@ -18,38 +18,40 @@ this.EXPORTED_SYMBOLS = [
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
                                    "@mozilla.org/uuid-generator;1",
                                    "nsIUUIDGenerator");
 
-XPCOMUtils.defineLazyGetter(this, "logger", function() {
-  Cu.import('resource://gre/modules/identity/LogUtils.jsm');
-  return getLogger("Identity", "toolkit.identity.debug");
-});
+XPCOMUtils.defineLazyModuleGetter(this, "Logger",
+                                  "resource://gre/modules/identity/LogUtils.jsm");
+
+function log(...aMessageArgs) {
+  Logger.log.apply(Logger, ["Identity"].concat(aMessageArgs));
+}
 
 function defined(item) {
   return typeof item !== 'undefined';
 }
 
 var checkDeprecated = this.checkDeprecated = function checkDeprecated(aOptions, aField) {
   if (defined(aOptions[aField])) {
-    logger.log("WARNING: field is deprecated:", aField);
+    log("WARNING: field is deprecated:", aField);
     return true;
   }
   return false;
 };
 
 this.checkRenamed = function checkRenamed(aOptions, aOldName, aNewName) {
   if (defined(aOptions[aOldName]) &&
       defined(aOptions[aNewName])) {
     let err = "You cannot provide both " + aOldName + " and " + aNewName;
-    logger.error(err);
+    Logger.reportError(err);
     throw new Error(err);
   }
 
   if (checkDeprecated(aOptions, aOldName)) {
     aOptions[aNewName] = aOptions[aOldName];
     delete(aOptions[aOldName]);
   }
 };
@@ -57,17 +59,17 @@ this.checkRenamed = function checkRename
 this.getRandomId = function getRandomId() {
   return uuidgen.generateUUID().toString();
 };
 
 /*
  * copy source object into target, excluding private properties
  * (those whose names begin with an underscore)
  */
-this.objectCopy = function objectCopy(source, target) {
+this.objectCopy = function objectCopy(source, target){
   let desc;
   Object.getOwnPropertyNames(source).forEach(function(name) {
     if (name[0] !== '_') {
       desc = Object.getOwnPropertyDescriptor(source, name);
       Object.defineProperty(target, name, desc);
     }
   });
 };
--- a/toolkit/identity/LogUtils.jsm
+++ b/toolkit/identity/LogUtils.jsm
@@ -1,178 +1,103 @@
 /* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 "use strict";
 
-this.EXPORTED_SYMBOLS = ["Logger", "getLogger"];
+this.EXPORTED_SYMBOLS = ["Logger"];
+const PREF_DEBUG = "toolkit.identity.debug";
 
 const Cu = Components.utils;
 const Ci = Components.interfaces;
+const Cc = Components.classes;
+const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
-function Logger(aIdentifier, aEnablingPref) {
-  this._identifier = aIdentifier;
-  this._enablingPref = aEnablingPref;
-
-  // Enabled by default if a pref for toggling the logger is not given
-  this._enabled = !this._enablingPref;
-
-  this.init();
+function IdentityLogger() {
+  Services.prefs.addObserver(PREF_DEBUG, this, false);
+  this._debug = Services.prefs.getBoolPref(PREF_DEBUG);
+  return this;
 }
 
-Logger.prototype = {
+IdentityLogger.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
 
-  init: function Logger_init() {
-    if (this._enablingPref) {
-      Services.prefs.addObserver(this._enablingPref, this, false);
-      this._enabled = Services.prefs.getBoolPref(this._enablingPref);
-    }
-  },
-
   observe: function observe(aSubject, aTopic, aData) {
-    switch (aTopic) {
+    switch(aTopic) {
       case "nsPref:changed":
-        this._enabled = Services.prefs.getBoolPref(this._enablingPref);
-        dump("LogUtils " +
-             (this._enabled ? "enabled" : "disabled") +
-             " for " + this._identifier + "\n");
+        this._debug = Services.prefs.getBoolPref(PREF_DEBUG);
         break;
 
       case "quit-application-granted":
-        Services.prefs.removeObserver(this._enablingPref, this);
+        Services.prefs.removeObserver(PREF_DEBUG, this);
         break;
 
       default:
         this.log("Logger observer", "Unknown topic:", aTopic);
         break;
     }
   },
 
-  _generatePrefix: function _generatePrefix() {
-    let caller = Components.stack.caller.caller;
-    let parts = ['[' + this._identifier + ']'];
+  _generateLogMessage: function _generateLogMessage(aPrefix, args) {
+    // create a string representation of a list of arbitrary things
+    let strings = [];
 
-    // filename could be like path/to/foo.js or Scratchpad/1
-    if (caller.filename) {
-      let path = caller.filename.split('/');
-      if (path[path.length - 1].match(/\./)) {
-        parts.push(path[path.length - 1])
-      } else {
-        parts.push(caller.filename);
-      }
-    }
+    // XXX bug 770418 - args look like flattened array, not list of strings
 
-    // Might not be called from a function; might be top-level
-    if (caller.name) {
-      parts.push(caller.name + '()');
-    }
-
-    parts.push('line ' + caller.lineNumber + ': ');
-
-    return parts.join(' ');
-  },
-
-  _generateLogMessage: function _generateLogMessage(severity, argList) {
-    let strings = [];
-    argList.forEach(function(arg) {
-      if (arg === null) {
+    args.forEach(function(arg) {
+      if (typeof arg === 'string') {
+        strings.push(arg);
+      } else if (typeof arg === 'undefined') {
+        strings.push('undefined');
+      } else if (arg === null) {
         strings.push('null');
       } else {
-        switch (typeof arg) {
-          case 'string':
-            strings.push(arg);
-            break;
-          case 'undefined':
-            strings.push('undefined');
-            break;
-          case 'function':
-            strings.push('<<function>>');
-            break;
-          case 'object':
-            try {
-              strings.push(JSON.stringify(arg, null, 2));
-            } catch (err) {
-              strings.push('<<object>>');
-            }
-            break;
-          default:
-            try {
-              strings.push(arg.toString());
-            } catch (err) {
-              strings.push('<<something>>');
-            }
-            break;
+        try {
+          strings.push(JSON.stringify(arg, null, 2));
+        } catch(err) {
+          strings.push("<<something>>");
         }
       }
     });
-    return strings.join(' ');
+    return 'Identity ' + aPrefix + ': ' + strings.join(' ');
   },
 
   /**
    * log() - utility function to print a list of arbitrary things
    *
    * Enable with about:config pref toolkit.identity.debug
    */
-  log: function log(...argList) {
-    if (!this._enabled) {
+  log: function log(aPrefix, ...args) {
+    if (!this._debug) {
       return;
     }
-    let output = this._generatePrefix() + this._generateLogMessage('info', argList);
+    let output = this._generateLogMessage(aPrefix, args);
+    dump(output + "\n");
 
-    // print to the shell console and the browser error console
-    dump(output + "\n");
+    // Additionally, make the output visible in the Error Console
     Services.console.logStringMessage(output);
   },
 
-  warning: function Logger_warning(...argList) {
-    if (!this._enabled) {
-      return;
-    }
-
-    let output = this._generatePrefix() + this._generateLogMessage('warning', argList);
-  },
-
   /**
-   * error() - report an error through component utils as well as
+   * reportError() - report an error through component utils as well as
    * our log function
    */
-  error: function Logger_error(...argList) {
-    if (!this._enabled) {
-      return;
-    }
+  reportError: function reportError(aPrefix, ...aArgs) {
+    let prefix = aPrefix + ' ERROR';
 
     // Report the error in the browser
-    let output = this._generatePrefix() + this._generateLogMessage('error', argList);
+    let output = this._generateLogMessage(aPrefix, aArgs);
     Cu.reportError(output);
-
-    // print to the console
     dump("ERROR: " + output + "\n");
-    dump("   traceback follows:\n");
     for (let frame = Components.stack.caller; frame; frame = frame.caller) {
       dump(frame + "\n");
     }
   }
+
 };
 
-/**
- * let logger = getLogger('my component', 'toolkit.foo.debug');
- * logger.log("I would like", 42, "pies", {'and-some': 'object'});
- */
-
-let _loggers = {};
-
-this.getLogger = function(aIdentifier, aEnablingPref) {
-  let key = aIdentifier;
-  if (aEnablingPref) {
-    key = key + '-' + aEnablingPref;
-  }
-  if (!_loggers[key]) {
-    _loggers[key] = new Logger(aIdentifier, aEnablingPref);
-  }
-  return _loggers[key];
-}
+this.Logger = new IdentityLogger();
--- a/toolkit/identity/MinimalIdentity.jsm
+++ b/toolkit/identity/MinimalIdentity.jsm
@@ -14,25 +14,34 @@
  */
 
 "use strict";
 
 this.EXPORTED_SYMBOLS = ["IdentityService"];
 
 const Cu = Components.utils;
 const Ci = Components.interfaces;
+const Cc = Components.classes;
+const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/identity/LogUtils.jsm");
 Cu.import("resource://gre/modules/identity/IdentityUtils.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "logger", function() {
-  Cu.import('resource://gre/modules/identity/LogUtils.jsm');
-  return getLogger("Identity", "toolkit.identity.debug");
-});
+XPCOMUtils.defineLazyModuleGetter(this,
+                                  "jwcrypto",
+                                  "resource://gre/modules/identity/jwcrypto.jsm");
+
+function log(...aMessageArgs) {
+  Logger.log.apply(Logger, ["minimal core"].concat(aMessageArgs));
+}
+function reportError(...aMessageArgs) {
+  Logger.reportError.apply(Logger, ["core"].concat(aMessageArgs));
+}
 
 function makeMessageObject(aRpCaller) {
   let options = {};
 
   options.id = aRpCaller.id;
   options.origin = aRpCaller.origin;
 
   // loggedInUser can be undefined, null, or a string
@@ -50,48 +59,64 @@ function makeMessageObject(aRpCaller) {
       options[option] = aRpCaller[option];
     }
   });
 
   // check validity of message structure
   if ((typeof options.id === 'undefined') ||
       (typeof options.origin === 'undefined')) {
     let err = "id and origin required in relying-party message: " + JSON.stringify(options);
-    logger.error(err);
+    reportError(err);
     throw new Error(err);
   }
 
   return options;
 }
 
 function IDService() {
   Services.obs.addObserver(this, "quit-application-granted", false);
+  // Services.obs.addObserver(this, "identity-auth-complete", false);
 
   // simplify, it's one object
   this.RP = this;
   this.IDP = this;
 
   // keep track of flows
   this._rpFlows = {};
   this._authFlows = {};
   this._provFlows = {};
 }
 
 IDService.prototype = {
   QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
 
-  observe: function IDService_observe(aSubject, aTopic, aData) {
+  observe: function observe(aSubject, aTopic, aData) {
     switch (aTopic) {
       case "quit-application-granted":
         Services.obs.removeObserver(this, "quit-application-granted");
+        // Services.obs.removeObserver(this, "identity-auth-complete");
         break;
     }
   },
 
   /**
+   * Parse an email into username and domain if it is valid, else return null
+   */
+  parseEmail: function parseEmail(email) {
+    var match = email.match(/^([^@]+)@([^@^/]+.[a-z]+)$/);
+    if (match) {
+      return {
+        username: match[1],
+        domain: match[2]
+      };
+    }
+    return null;
+  },
+
+  /**
    * Register a listener for a given windowID as a result of a call to
    * navigator.id.watch().
    *
    * @param aCaller
    *        (Object)  an object that represents the caller document, and
    *                  is expected to have properties:
    *                  - id (unique, e.g. uuid)
    *                  - loggedInUser (string or null)
@@ -100,51 +125,51 @@ IDService.prototype = {
    *                  and a bunch of callbacks
    *                  - doReady()
    *                  - doLogin()
    *                  - doLogout()
    *                  - doError()
    *                  - doCancel()
    *
    */
-  watch: function IDService_watch(aRpCaller) {
+  watch: function watch(aRpCaller) {
     // store the caller structure and notify the UI observers
     this._rpFlows[aRpCaller.id] = aRpCaller;
 
     let options = makeMessageObject(aRpCaller);
-    logger.log("sending identity-controller-watch:", options);
+    log("sending identity-controller-watch:", options);
     Services.obs.notifyObservers({wrappedJSObject: options},"identity-controller-watch", null);
   },
 
   /*
    * The RP has gone away; remove handles to the hidden iframe.
    * It's probable that the frame will already have been cleaned up.
    */
-  unwatch: function IDService_unwatch(aRpId, aTargetMM) {
+  unwatch: function unwatch(aRpId, aTargetMM) {
     let rp = this._rpFlows[aRpId];
     let options = makeMessageObject({
       id: aRpId,
       origin: rp.origin,
       messageManager: aTargetMM
     });
-    logger.log("sending identity-controller-unwatch for id", options.id, options.origin);
+    log("sending identity-controller-unwatch for id", options.id, options.origin);
     Services.obs.notifyObservers({wrappedJSObject: options}, "identity-controller-unwatch", null);
   },
 
   /**
    * Initiate a login with user interaction as a result of a call to
    * navigator.id.request().
    *
    * @param aRPId
    *        (integer)  the id of the doc object obtained in .watch()
    *
    * @param aOptions
    *        (Object)  options including privacyPolicy, termsOfService
    */
-  request: function IDService_request(aRPId, aOptions) {
+  request: function request(aRPId, aOptions) {
     let rp = this._rpFlows[aRPId];
 
     // Notify UX to display identity picker.
     // Pass the doc id to UX so it can pass it back to us later.
     let options = makeMessageObject(rp);
     objectCopy(aOptions, options);
     Services.obs.notifyObservers({wrappedJSObject: options}, "identity-controller-request", null);
   },
@@ -152,74 +177,269 @@ IDService.prototype = {
   /**
    * Invoked when a user wishes to logout of a site (for instance, when clicking
    * on an in-content logout button).
    *
    * @param aRpCallerId
    *        (integer)  the id of the doc object obtained in .watch()
    *
    */
-  logout: function IDService_logout(aRpCallerId) {
+  logout: function logout(aRpCallerId) {
     let rp = this._rpFlows[aRpCallerId];
 
     let options = makeMessageObject(rp);
     Services.obs.notifyObservers({wrappedJSObject: options}, "identity-controller-logout", null);
   },
 
-  childProcessShutdown: function IDService_childProcessShutdown(messageManager) {
+  childProcessShutdown: function childProcessShutdown(messageManager) {
     let options = makeMessageObject({messageManager: messageManager, id: null, origin: null});
     Services.obs.notifyObservers({wrappedJSObject: options}, "identity-child-process-shutdown", null);
     Object.keys(this._rpFlows).forEach(function(key) {
       if (this._rpFlows[key]._mm === messageManager) {
-        logger.log("child process shutdown for rp", key, "- deleting flow");
+        log("child process shutdown for rp", key, "- deleting flow");
         delete this._rpFlows[key];
       }
     }, this);
   },
 
   /*
    * once the UI-and-display-logic components have received
    * notifications, they call back with direct invocation of the
    * following functions (doLogin, doLogout, or doReady)
    */
 
-  doLogin: function IDService_doLogin(aRpCallerId, aAssertion, aInternalParams) {
+  doLogin: function doLogin(aRpCallerId, aAssertion, aInternalParams) {
     let rp = this._rpFlows[aRpCallerId];
     if (!rp) {
       dump("WARNING: doLogin found no rp to go with callerId " + aRpCallerId + "\n");
       return;
     }
 
     rp.doLogin(aAssertion, aInternalParams);
   },
 
-  doLogout: function IDService_doLogout(aRpCallerId) {
+  doLogout: function doLogout(aRpCallerId) {
     let rp = this._rpFlows[aRpCallerId];
     if (!rp) {
       dump("WARNING: doLogout found no rp to go with callerId " + aRpCallerId + "\n");
       return;
     }
 
     rp.doLogout();
   },
 
-  doReady: function IDService_doReady(aRpCallerId) {
+  doReady: function doReady(aRpCallerId) {
     let rp = this._rpFlows[aRpCallerId];
     if (!rp) {
       dump("WARNING: doReady found no rp to go with callerId " + aRpCallerId + "\n");
       return;
     }
 
     rp.doReady();
   },
 
-  doCancel: function IDService_doCancel(aRpCallerId) {
+  doCancel: function doCancel(aRpCallerId) {
     let rp = this._rpFlows[aRpCallerId];
     if (!rp) {
       dump("WARNING: doCancel found no rp to go with callerId " + aRpCallerId + "\n");
       return;
     }
 
     rp.doCancel();
-  }
+  },
+
+
+  /*
+   * XXX Bug 804229: Implement Identity Provider Functions
+   *
+   * Stubs for Identity Provider functions follow
+   */
+
+  /**
+   * the provisioning iframe sandbox has called navigator.id.beginProvisioning()
+   *
+   * @param aCaller
+   *        (object)  the iframe sandbox caller with all callbacks and
+   *                  other information.  Callbacks include:
+   *                  - doBeginProvisioningCallback(id, duration_s)
+   *                  - doGenKeyPairCallback(pk)
+   */
+  beginProvisioning: function beginProvisioning(aCaller) {
+  },
+
+  /**
+   * the provisioning iframe sandbox has called
+   * navigator.id.raiseProvisioningFailure()
+   *
+   * @param aProvId
+   *        (int)  the identifier of the provisioning flow tied to that sandbox
+   * @param aReason
+   */
+  raiseProvisioningFailure: function raiseProvisioningFailure(aProvId, aReason) {
+    reportError("Provisioning failure", aReason);
+  },
+
+  /**
+   * When navigator.id.genKeyPair is called from provisioning iframe sandbox.
+   * Generates a keypair for the current user being provisioned.
+   *
+   * @param aProvId
+   *        (int)  the identifier of the provisioning caller tied to that sandbox
+   *
+   * It is an error to call genKeypair without receiving the callback for
+   * the beginProvisioning() call first.
+   */
+  genKeyPair: function genKeyPair(aProvId) {
+  },
+
+  /**
+   * When navigator.id.registerCertificate is called from provisioning iframe
+   * sandbox.
+   *
+   * Sets the certificate for the user for which a certificate was requested
+   * via a preceding call to beginProvisioning (and genKeypair).
+   *
+   * @param aProvId
+   *        (integer) the identifier of the provisioning caller tied to that
+   *                  sandbox
+   *
+   * @param aCert
+   *        (String)  A JWT representing the signed certificate for the user
+   *                  being provisioned, provided by the IdP.
+   */
+  registerCertificate: function registerCertificate(aProvId, aCert) {
+  },
+
+  /**
+   * The authentication frame has called navigator.id.beginAuthentication
+   *
+   * IMPORTANT: the aCaller is *always* non-null, even if this is called from
+   * a regular content page. We have to make sure, on every DOM call, that
+   * aCaller is an expected authentication-flow identifier. If not, we throw
+   * an error or something.
+   *
+   * @param aCaller
+   *        (object)  the authentication caller
+   *
+   */
+  beginAuthentication: function beginAuthentication(aCaller) {
+  },
+
+  /**
+   * The auth frame has called navigator.id.completeAuthentication
+   *
+   * @param aAuthId
+   *        (int)  the identifier of the authentication caller tied to that sandbox
+   *
+   */
+  completeAuthentication: function completeAuthentication(aAuthId) {
+  },
+
+  /**
+   * The auth frame has called navigator.id.cancelAuthentication
+   *
+   * @param aAuthId
+   *        (int)  the identifier of the authentication caller
+   *
+   */
+  cancelAuthentication: function cancelAuthentication(aAuthId) {
+  },
+
+  // methods for chrome and add-ons
+
+  /**
+   * Discover the IdP for an identity
+   *
+   * @param aIdentity
+   *        (string) the email we're logging in with
+   *
+   * @param aCallback
+   *        (function) callback to invoke on completion
+   *                   with first-positional parameter the error.
+   */
+  _discoverIdentityProvider: function _discoverIdentityProvider(aIdentity, aCallback) {
+    // XXX bug 767610 - validate email address call
+    // When that is available, we can remove this custom parser
+    var parsedEmail = this.parseEmail(aIdentity);
+    if (parsedEmail === null) {
+      return aCallback("Could not parse email: " + aIdentity);
+    }
+    log("_discoverIdentityProvider: identity:", aIdentity, "domain:", parsedEmail.domain);
+
+    this._fetchWellKnownFile(parsedEmail.domain, function fetchedWellKnown(err, idpParams) {
+      // idpParams includes the pk, authorization url, and
+      // provisioning url.
+
+      // XXX bug 769861 follow any authority delegations
+      // if no well-known at any point in the delegation
+      // fall back to browserid.org as IdP
+      return aCallback(err, idpParams);
+    });
+  },
+
+  /**
+   * Fetch the well-known file from the domain.
+   *
+   * @param aDomain
+   *
+   * @param aScheme
+   *        (string) (optional) Protocol to use.  Default is https.
+   *                 This is necessary because we are unable to test
+   *                 https.
+   *
+   * @param aCallback
+   *
+   */
+  _fetchWellKnownFile: function _fetchWellKnownFile(aDomain, aCallback, aScheme='https') {
+    // XXX bug 769854 make tests https and remove aScheme option
+    let url = aScheme + '://' + aDomain + "/.well-known/browserid";
+    log("_fetchWellKnownFile:", url);
+
+    // this appears to be a more successful way to get at xmlhttprequest (which supposedly will close with a window
+    let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"]
+                .createInstance(Ci.nsIXMLHttpRequest);
+
+    // XXX bug 769865 gracefully handle being off-line
+    // XXX bug 769866 decide on how to handle redirects
+    req.open("GET", url, true);
+    req.responseType = "json";
+    req.mozBackgroundRequest = true;
+    req.onload = function _fetchWellKnownFile_onload() {
+      if (req.status < 200 || req.status >= 400) {
+        log("_fetchWellKnownFile", url, ": server returned status:", req.status);
+        return aCallback("Error");
+      }
+      try {
+        let idpParams = req.response;
+
+        // Verify that the IdP returned a valid configuration
+        if (! (idpParams.provisioning &&
+            idpParams.authentication &&
+            idpParams['public-key'])) {
+          let errStr= "Invalid well-known file from: " + aDomain;
+          log("_fetchWellKnownFile:", errStr);
+          return aCallback(errStr);
+        }
+
+        let callbackObj = {
+          domain: aDomain,
+          idpParams: idpParams,
+        };
+        log("_fetchWellKnownFile result: ", callbackObj);
+        // Yay.  Valid IdP configuration for the domain.
+        return aCallback(null, callbackObj);
+
+      } catch (err) {
+        reportError("_fetchWellKnownFile", "Bad configuration from", aDomain, err);
+        return aCallback(err.toString());
+      }
+    };
+    req.onerror = function _fetchWellKnownFile_onerror() {
+      log("_fetchWellKnownFile", "ERROR:", req.status, req.statusText);
+      log("ERROR: _fetchWellKnownFile:", err);
+      return aCallback("Error");
+    };
+    req.send(null);
+  },
+
 };
 
 this.IdentityService = new IDService();
--- a/toolkit/identity/RelyingParty.jsm
+++ b/toolkit/identity/RelyingParty.jsm
@@ -8,29 +8,32 @@
 
 const Cu = Components.utils;
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/identity/LogUtils.jsm");
 Cu.import("resource://gre/modules/identity/IdentityUtils.jsm");
 Cu.import("resource://gre/modules/identity/IdentityStore.jsm");
 
 this.EXPORTED_SYMBOLS = ["RelyingParty"];
 
 XPCOMUtils.defineLazyModuleGetter(this,
                                   "jwcrypto",
                                   "resource://gre/modules/identity/jwcrypto.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "logger", function() {
-  Cu.import('resource://gre/modules/identity/LogUtils.jsm');
-  return getLogger("Identity RP", "toolkit.identity.debug");
-});
+function log(...aMessageArgs) {
+  Logger.log.apply(Logger, ["RP"].concat(aMessageArgs));
+}
+function reportError(...aMessageArgs) {
+  Logger.reportError.apply(Logger, ["RP"].concat(aMessageArgs));
+}
 
 function IdentityRelyingParty() {
   // The store is a singleton shared among Identity, RelyingParty, and
   // IdentityProvider.  The Identity module takes care of resetting
   // state in the _store on shutdown.
   this._store = IdentityStore;
 
   this.reset();
@@ -79,17 +82,17 @@ IdentityRelyingParty.prototype = {
    *                  - doCancel()
    *
    */
   watch: function watch(aRpCaller) {
     this._rpFlows[aRpCaller.id] = aRpCaller;
     let origin = aRpCaller.origin;
     let state = this._store.getLoginState(origin) || { isLoggedIn: false, email: null };
 
-    logger.log("watch: rpId:", aRpCaller.id,
+    log("watch: rpId:", aRpCaller.id,
         "origin:", origin,
         "loggedInUser:", aRpCaller.loggedInUser,
         "loggedIn:", state.isLoggedIn,
         "email:", state.email);
 
     // If the user is already logged in, then there are three cases
     // to deal with:
     //
@@ -131,45 +134,45 @@ IdentityRelyingParty.prototype = {
 
   /**
    * A utility for watch() to set state and notify the dom
    * on login
    *
    * Note that this calls _getAssertion
    */
   _doLogin: function _doLogin(aRpCaller, aOptions, aAssertion) {
-    logger.log("_doLogin: rpId:", aRpCaller.id, "origin:", aOptions.origin);
+    log("_doLogin: rpId:", aRpCaller.id, "origin:", aOptions.origin);
 
     let loginWithAssertion = function loginWithAssertion(assertion) {
       this._store.setLoginState(aOptions.origin, true, aOptions.loggedInUser);
       this._notifyLoginStateChanged(aRpCaller.id, aOptions.loggedInUser);
       aRpCaller.doLogin(assertion);
       aRpCaller.doReady();
     }.bind(this);
 
     if (aAssertion) {
       loginWithAssertion(aAssertion);
     } else {
       this._getAssertion(aOptions, function gotAssertion(err, assertion) {
         if (err) {
-          logger.warning("_doLogin:", "Failed to get assertion on login attempt:", err);
+          reportError("_doLogin:", "Failed to get assertion on login attempt:", err);
           this._doLogout(aRpCaller);
         } else {
           loginWithAssertion(assertion);
         }
       }.bind(this));
     }
   },
 
   /**
    * A utility for watch() to set state and notify the dom
    * on logout.
    */
   _doLogout: function _doLogout(aRpCaller, aOptions) {
-    logger.log("_doLogout: rpId:", aRpCaller.id, "origin:", aOptions.origin);
+    log("_doLogout: rpId:", aRpCaller.id, "origin:", aOptions.origin);
 
     let state = this._store.getLoginState(aOptions.origin) || {};
 
     state.isLoggedIn = false;
     this._notifyLoginStateChanged(aRpCaller.id, null);
 
     aRpCaller.doLogout();
     aRpCaller.doReady();
@@ -183,17 +186,17 @@ IdentityRelyingParty.prototype = {
    *
    * @param aRpCallerId
    *        (integer) The id of the RP caller
    *
    * @param aIdentity
    *        (string) The email of the user whose login state has changed
    */
   _notifyLoginStateChanged: function _notifyLoginStateChanged(aRpCallerId, aIdentity) {
-    logger.log("_notifyLoginStateChanged: rpId:", aRpCallerId, "identity:", aIdentity);
+    log("_notifyLoginStateChanged: rpId:", aRpCallerId, "identity:", aIdentity);
 
     let options = {rpId: aRpCallerId};
     Services.obs.notifyObservers({wrappedJSObject: options},
                                  "identity-login-state-changed",
                                  aIdentity);
   },
 
   /**
@@ -202,17 +205,17 @@ IdentityRelyingParty.prototype = {
    *
    * @param aRPId
    *        (integer)  the id of the doc object obtained in .watch()
    *
    * @param aOptions
    *        (Object)  options including privacyPolicy, termsOfService
    */
   request: function request(aRPId, aOptions) {
-    logger.log("request: rpId:", aRPId);
+    log("request: rpId:", aRPId);
     let rp = this._rpFlows[aRPId];
 
     // Notify UX to display identity picker.
     // Pass the doc id to UX so it can pass it back to us later.
     let options = {rpId: aRPId, origin: rp.origin};
     objectCopy(aOptions, options);
 
     // Append URLs after resolving
@@ -230,33 +233,33 @@ IdentityRelyingParty.prototype = {
    * Invoked when a user wishes to logout of a site (for instance, when clicking
    * on an in-content logout button).
    *
    * @param aRpCallerId
    *        (integer)  the id of the doc object obtained in .watch()
    *
    */
   logout: function logout(aRpCallerId) {
-    logger.log("logout: RP caller id:", aRpCallerId);
+    log("logout: RP caller id:", aRpCallerId);
     let rp = this._rpFlows[aRpCallerId];
     if (rp && rp.origin) {
       let origin = rp.origin;
-      logger.log("logout: origin:", origin);
+      log("logout: origin:", origin);
       this._doLogout(rp, {origin: origin});
     } else {
-      logger.log("logout: no RP found with id:", aRpCallerId);
+      log("logout: no RP found with id:", aRpCallerId);
     }
     // We don't delete this._rpFlows[aRpCallerId], because
     // the user might log back in again.
   },
 
   getDefaultEmailForOrigin: function getDefaultEmailForOrigin(aOrigin) {
     let identities = this.getIdentitiesForSite(aOrigin);
     let result = identities.lastUsed || null;
-    logger.log("getDefaultEmailForOrigin:", aOrigin, "->", result);
+    log("getDefaultEmailForOrigin:", aOrigin, "->", result);
     return result;
   },
 
   /**
    * Return the list of identities a user may want to use to login to aOrigin.
    */
   getIdentitiesForSite: function getIdentitiesForSite(aOrigin) {
     let rv = { result: [] };
@@ -285,33 +288,33 @@ IdentityRelyingParty.prototype = {
    *                            issued. If this property is not set an exception
    *                            will be thrown.
    *
    *        Any properties not listed above will be ignored.
    */
   _getAssertion: function _getAssertion(aOptions, aCallback) {
     let audience = aOptions.origin;
     let email = aOptions.loggedInUser || this.getDefaultEmailForOrigin(audience);
-    logger.log("_getAssertion: audience:", audience, "email:", email);
+    log("_getAssertion: audience:", audience, "email:", email);
     if (!audience) {
       throw "audience required for _getAssertion";
     }
 
     // We might not have any identity info for this email
     if (!this._store.fetchIdentity(email)) {
       this._store.addIdentity(email, null, null);
     }
 
     let cert = this._store.fetchIdentity(email)['cert'];
     if (cert) {
       this._generateAssertion(audience, email, function generatedAssertion(err, assertion) {
         if (err) {
-          logger.warning("ERROR: _getAssertion:", err);
+          log("ERROR: _getAssertion:", err);
         }
-        logger.log("_getAssertion: generated assertion:", assertion);
+        log("_getAssertion: generated assertion:", assertion);
         return aCallback(err, assertion);
       });
     }
   },
 
   /**
    * Generate an assertion, including provisioning via IdP if necessary,
    * but no user interaction, so if provisioning fails, aCallback is invoked
@@ -323,45 +326,45 @@ IdentityRelyingParty.prototype = {
    * @param aIdentity
    *        (string) the email we're logging in with
    *
    * @param aCallback
    *        (function) callback to invoke on completion
    *                   with first-positional parameter the error.
    */
   _generateAssertion: function _generateAssertion(aAudience, aIdentity, aCallback) {
-    logger.log("_generateAssertion: audience:", aAudience, "identity:", aIdentity);
+    log("_generateAssertion: audience:", aAudience, "identity:", aIdentity);
 
     let id = this._store.fetchIdentity(aIdentity);
     if (! (id && id.cert)) {
       let errStr = "Cannot generate an assertion without a certificate";
-      logger.log("ERROR: _generateAssertion:", errStr);
+      log("ERROR: _generateAssertion:", errStr);
       aCallback(errStr);
       return;
     }
 
     let kp = id.keyPair;
 
     if (!kp) {
       let errStr = "Cannot generate an assertion without a keypair";
-      logger.log("ERROR: _generateAssertion:", errStr);
+      log("ERROR: _generateAssertion:", errStr);
       aCallback(errStr);
       return;
     }
 
     jwcrypto.generateAssertion(id.cert, kp, aAudience, aCallback);
   },
 
   /**
    * Clean up references to the provisioning flow for the specified RP.
    */
   _cleanUpProvisionFlow: function RP_cleanUpProvisionFlow(aRPId, aProvId) {
     let rp = this._rpFlows[aRPId];
     if (rp) {
       delete rp['provId'];
     } else {
-      logger.log("Error: Couldn't delete provision flow ", aProvId, " for RP ", aRPId);
+      log("Error: Couldn't delete provision flow ", aProvId, " for RP ", aRPId);
     }
   },
 
 };
 
 this.RelyingParty = new IdentityRelyingParty();
--- a/toolkit/identity/Sandbox.jsm
+++ b/toolkit/identity/Sandbox.jsm
@@ -8,20 +8,19 @@ this.EXPORTED_SYMBOLS = ["Sandbox"];
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 
 const XHTML_NS = "http://www.w3.org/1999/xhtml";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "logger", function() {
-  Cu.import('resource://gre/modules/identity/LogUtils.jsm');
-  return getLogger("Identity", "toolkit.identity.debug");
-});
+XPCOMUtils.defineLazyModuleGetter(this,
+                                  "Logger",
+                                  "resource://gre/modules/identity/LogUtils.jsm");
 
 /**
  * An object that represents a sandbox in an iframe loaded with aURL. The
  * callback provided to the constructor will be invoked when the sandbox is
  * ready to be used. The callback will receive this object as its only argument.
  *
  * You must call free() when you are finished with the sandbox to explicitly
  * free up all associated resources.
@@ -30,17 +29,17 @@ XPCOMUtils.defineLazyGetter(this, "logge
  *        (string) URL to load in the sandbox.
  *
  * @param aCallback
  *        (function) Callback to be invoked with a Sandbox, when ready.
  */
 this.Sandbox = function Sandbox(aURL, aCallback) {
   // Normalize the URL so the comparison in _makeSandboxContentLoaded works
   this._url = Services.io.newURI(aURL, null, null).spec;
-  logger.log("Creating sandbox for:", this._url);
+  this._log("Creating sandbox for:", this._url);
   this._createFrame();
   this._createSandbox(aCallback);
 };
 
 this.Sandbox.prototype = {
 
   /**
    * Use the outer window ID as the identifier of the sandbox.
@@ -50,28 +49,28 @@ this.Sandbox.prototype = {
                .getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
   },
 
   /**
    * Reload the URL in the sandbox. This is useful to reuse a Sandbox (same
    * id and URL).
    */
   reload: function Sandbox_reload(aCallback) {
-    logger.log("reload:", this.id, ":", this._url);
+    this._log("reload:", this.id, ":", this._url);
     this._createSandbox(function createdSandbox(aSandbox) {
-      logger.log("reloaded sandbox id:", aSandbox.id);
+      this._log("reloaded sandbox id:", aSandbox.id);
       aCallback(aSandbox);
     }.bind(this));
   },
 
   /**
    * Frees the sandbox and releases the iframe created to host it.
    */
   free: function Sandbox_free() {
-    logger.log("free:", this.id);
+    this._log("free:", this.id);
     this._container.removeChild(this._frame);
     this._frame = null;
     this._container = null;
     this._url = null;
   },
 
   /**
    * Creates an empty, hidden iframe and sets it to the _frame
@@ -111,17 +110,17 @@ this.Sandbox.prototype = {
     // Set instance properties.
     this._frame = frame;
     this._container = doc.documentElement;
   },
 
   _createSandbox: function Sandbox__createSandbox(aCallback) {
     let self = this;
     function _makeSandboxContentLoaded(event) {
-      logger.log("_makeSandboxContentLoaded:", self.id,
+      self._log("_makeSandboxContentLoaded:", self.id,
                 event.target.location.toString());
       if (event.target != self._frame.contentDocument) {
         return;
       }
       self._frame.removeEventListener(
         "DOMWindowCreated", _makeSandboxContentLoaded, true
       );
 
@@ -140,10 +139,15 @@ this.Sandbox.prototype = {
     webNav.loadURI(
       this._url,
       Ci.nsIWebNavigation.LOAD_FLAGS_BYPASS_CACHE,
       null, // referrer
       null, // postData
       null  // headers
     );
 
-  }
+  },
+
+  _log: function Sandbox__log(...aMessageArgs) {
+    Logger.log.apply(Logger, ["sandbox"].concat(aMessageArgs));
+  },
+
 };
--- a/toolkit/identity/jwcrypto.jsm
+++ b/toolkit/identity/jwcrypto.jsm
@@ -9,33 +9,33 @@
 
 const Cu = Components.utils;
 const Ci = Components.interfaces;
 const Cc = Components.classes;
 const Cr = Components.results;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyGetter(this, "logger", function() {
-  Cu.import('resource://gre/modules/identity/LogUtils.jsm');
-  return getLogger("Identity test", "toolkit.identity.debug");
-});
+Cu.import("resource://gre/modules/identity/LogUtils.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this,
                                    "IdentityCryptoService",
                                    "@mozilla.org/identity/crypto-service;1",
                                    "nsIIdentityCryptoService");
 
 this.EXPORTED_SYMBOLS = ["jwcrypto"];
 
 const ALGORITHMS = { RS256: "RS256", DS160: "DS160" };
 
+function log(...aMessageArgs) {
+  Logger.log.apply(Logger, ["jwcrypto"].concat(aMessageArgs));
+}
+
 function generateKeyPair(aAlgorithmName, aCallback) {
-  logger.log("Generate key pair; alg =", aAlgorithmName);
+  log("Generate key pair; alg =", aAlgorithmName);
 
   IdentityCryptoService.generateKeyPair(aAlgorithmName, function(rv, aKeyPair) {
     if (!Components.isSuccessCode(rv)) {
       return aCallback("key generation failed");
     }
 
     var publicKey;
 
@@ -69,36 +69,36 @@ function generateKeyPair(aAlgorithmName,
 
     return aCallback(null, keyWrapper);
   });
 }
 
 function sign(aPayload, aKeypair, aCallback) {
   aKeypair._kp.sign(aPayload, function(rv, signature) {
     if (!Components.isSuccessCode(rv)) {
-      logger.warning("ERROR: signer.sign failed");
+      log("ERROR: signer.sign failed");
       return aCallback("Sign failed");
     }
-    logger.log("signer.sign: success");
+    log("signer.sign: success");
     return aCallback(null, signature);
   });
 }
 
 function jwcryptoClass()
 {
 }
 
 jwcryptoClass.prototype = {
   isCertValid: function(aCert, aCallback) {
     // XXX check expiration, bug 769850
     aCallback(true);
   },
 
   generateKeyPair: function(aAlgorithmName, aCallback) {
-    logger.log("generating");
+    log("generating");
     generateKeyPair(aAlgorithmName, aCallback);
   },
 
   generateAssertion: function(aCert, aKeyPair, aAudience, aCallback) {
     // for now, we hack the algorithm name
     // XXX bug 769851
     var header = {"alg": "DS128"};
     var headerBytes = IdentityCryptoService.base64UrlEncode(
@@ -108,17 +108,17 @@ jwcryptoClass.prototype = {
       // expires in 2 minutes
       // XXX clock skew needs exploration bug 769852
       exp: Date.now() + (2 * 60 * 1000),
       aud: aAudience
     };
     var payloadBytes = IdentityCryptoService.base64UrlEncode(
                           JSON.stringify(payload));
 
-    logger.log("payload bytes", payload, payloadBytes);
+    log("payload bytes", payload, payloadBytes);
     sign(headerBytes + "." + payloadBytes, aKeyPair, function(err, signature) {
       if (err)
         return aCallback(err);
 
       var signedAssertion = headerBytes + "." + payloadBytes + "." + signature;
       return aCallback(null, aCert + "~" + signedAssertion);
     });
   }
--- a/toolkit/identity/tests/unit/head_identity.js
+++ b/toolkit/identity/tests/unit/head_identity.js
@@ -20,16 +20,20 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "IDService",
                                   "resource://gre/modules/identity/Identity.jsm",
                                   "IdentityService");
 
 XPCOMUtils.defineLazyModuleGetter(this,
                                   "IdentityStore",
                                   "resource://gre/modules/identity/IdentityStore.jsm");
 
+XPCOMUtils.defineLazyModuleGetter(this,
+                                  "Logger",
+                                  "resource://gre/modules/identity/LogUtils.jsm");
+
 XPCOMUtils.defineLazyServiceGetter(this,
                                    "uuidGenerator",
                                    "@mozilla.org/uuid-generator;1",
                                    "nsIUUIDGenerator");
 
 const TEST_URL = "https://myfavoritebacon.com";
 const TEST_URL2 = "https://myfavoritebaconinacan.com";
 const TEST_USER = "user@mozilla.com";
@@ -66,23 +70,20 @@ let XULAppInfoFactory = {
 };
 
 let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
 registrar.registerFactory(Components.ID("{fbfae60b-64a4-44ef-a911-08ceb70b9f31}"),
                           "XULAppInfo", "@mozilla.org/xre/app-info;1",
                           XULAppInfoFactory);
 
 // The following are utility functions for Identity testing
-//
-XPCOMUtils.defineLazyGetter(this, "logger", function() {
-  Cu.import('resource://gre/modules/identity/LogUtils.jsm');
-  return getLogger("Identity test", "toolkit.identity.debug");
-});
 
-var log = logger.log;
+function log(...aMessageArgs) {
+  Logger.log.apply(Logger, ["test"].concat(aMessageArgs));
+}
 
 function get_idstore() {
   return IdentityStore;
 }
 
 function partial(fn) {
   let args = Array.prototype.slice.call(arguments, 1);
   return function() {
--- a/toolkit/identity/tests/unit/test_crypto_service.js
+++ b/toolkit/identity/tests/unit/test_crypto_service.js
@@ -1,68 +1,64 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyGetter(this, "logger", function() {
-  Cu.import('resource://gre/modules/identity/LogUtils.jsm');
-  return getLogger("Identity test", "toolkit.identity.debug");
-});
+Cu.import('resource://gre/modules/identity/LogUtils.jsm');
 
 const idService = Cc["@mozilla.org/identity/crypto-service;1"]
                     .getService(Ci.nsIIdentityCryptoService);
 
 const ALG_DSA = "DS160";
 const ALG_RSA = "RS256";
 
 // When the output of an operation is a
 function do_check_eq_or_slightly_less(x, y) {
   do_check_true(x >= y - (3 * 8));
 }
 
 function test_dsa() {
   idService.generateKeyPair(ALG_DSA, function (rv, keyPair) {
-    logger.log("DSA generateKeyPair finished ", rv);
+    log("DSA generateKeyPair finished ", rv);
     do_check_true(Components.isSuccessCode(rv));
     do_check_eq(typeof keyPair.sign, "function");
     do_check_eq(keyPair.keyType, ALG_DSA);
     do_check_eq_or_slightly_less(keyPair.hexDSAGenerator.length, 1024 / 8 * 2);
     do_check_eq_or_slightly_less(keyPair.hexDSAPrime.length, 1024 / 8 * 2);
     do_check_eq_or_slightly_less(keyPair.hexDSASubPrime.length, 160 / 8 * 2);
     do_check_eq_or_slightly_less(keyPair.hexDSAPublicValue.length, 1024 / 8 * 2);
     // XXX: test that RSA parameters throw the correct error
 
-    logger.log("about to sign with DSA key");
+    log("about to sign with DSA key");
     keyPair.sign("foo", function (rv, signature) {
-      logger.log("DSA sign finished ", rv, signature);
+      log("DSA sign finished ", rv, signature);
       do_check_true(Components.isSuccessCode(rv));
       do_check_true(signature.length > 1);
       // TODO: verify the signature with the public key
       run_next_test();
     });
   });
 }
 
 function test_rsa() {
   idService.generateKeyPair(ALG_RSA, function (rv, keyPair) {
-    logger.log("RSA generateKeyPair finished ", rv);
+    log("RSA generateKeyPair finished ", rv);
     do_check_true(Components.isSuccessCode(rv));
     do_check_eq(typeof keyPair.sign, "function");
     do_check_eq(keyPair.keyType, ALG_RSA);
     do_check_eq_or_slightly_less(keyPair.hexRSAPublicKeyModulus.length,
                                  2048 / 8);
     do_check_true(keyPair.hexRSAPublicKeyExponent.length > 1);
 
-    logger.log("about to sign with RSA key");
+    log("about to sign with RSA key");
     keyPair.sign("foo", function (rv, signature) {
-      logger.log("RSA sign finished ", rv, signature);
+      log("RSA sign finished ", rv, signature);
       do_check_true(Components.isSuccessCode(rv));
       do_check_true(signature.length > 1);
       run_next_test();
     });
   });
 }
 
 add_test(test_dsa);
--- a/toolkit/identity/tests/unit/test_jwcrypto.js
+++ b/toolkit/identity/tests/unit/test_jwcrypto.js
@@ -1,25 +1,22 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict"
 
+Cu.import('resource://gre/modules/identity/LogUtils.jsm');
+
 XPCOMUtils.defineLazyModuleGetter(this, "IDService",
                                   "resource://gre/modules/identity/Identity.jsm",
                                   "IdentityService");
 
 XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto",
                                   "resource://gre/modules/identity/jwcrypto.jsm");
 
-XPCOMUtils.defineLazyGetter(this, "logger", function() {
-  Cu.import('resource://gre/modules/identity/LogUtils.jsm');
-  return getLogger("Identity test", "toolkit.identity.debug");
-});
-
 const RP_ORIGIN = "http://123done.org";
 const INTERNAL_ORIGIN = "browserid://";
 
 function test_sanity() {
   do_test_pending();
 
   jwcrypto.generateKeyPair("DS160", function(err, kp) {
     do_check_null(err);
@@ -45,29 +42,29 @@ function test_get_assertion() {
 
   jwcrypto.generateKeyPair(
     "DS160",
     function(err, kp) {
       jwcrypto.generateAssertion("fake-cert", kp, RP_ORIGIN, function(err, assertion) {
         do_check_null(err);
 
         // more checks on assertion
-        logger.log("assertion", assertion);
+        log("assertion", assertion);
 
         do_test_finished();
         run_next_test();
       });
     });
 }
 
 function test_rsa() {
   do_test_pending();
   function checkRSA(err, kpo) {
     do_check_neq(kpo, undefined);
-    logger.log(kpo.serializedPublicKey);
+    log(kpo.serializedPublicKey);
     let pk = JSON.parse(kpo.serializedPublicKey);
     do_check_eq(pk.algorithm, "RS");
 /* TODO
     do_check_neq(kpo.sign, null);
     do_check_eq(typeof kpo.sign, "function");
     do_check_neq(kpo.userID, null);
     do_check_neq(kpo.url, null);
     do_check_eq(kpo.url, INTERNAL_ORIGIN);
@@ -87,17 +84,17 @@ function test_rsa() {
 
   jwcrypto.generateKeyPair("RS256", checkRSA);
 }
 
 function test_dsa() {
   do_test_pending();
   function checkDSA(err, kpo) {
     do_check_neq(kpo, undefined);
-    logger.log(kpo.serializedPublicKey);
+    log(kpo.serializedPublicKey);
     let pk = JSON.parse(kpo.serializedPublicKey);
     do_check_eq(pk.algorithm, "DS");
 /* TODO
     do_check_neq(kpo.sign, null);
     do_check_eq(typeof kpo.sign, "function");
     do_check_neq(kpo.userID, null);
     do_check_neq(kpo.url, null);
     do_check_eq(kpo.url, INTERNAL_ORIGIN);
--- a/toolkit/identity/tests/unit/test_log_utils.js
+++ b/toolkit/identity/tests/unit/test_log_utils.js
@@ -1,73 +1,74 @@
 
 "use strict";
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import('resource://gre/modules/Services.jsm');
-
-XPCOMUtils.defineLazyGetter(this, "logger", function() {
-  Cu.import('resource://gre/modules/identity/LogUtils.jsm');
-  return getLogger("Identity test", "toolkit.identity.debug");
-});
+Cu.import('resource://gre/modules/identity/LogUtils.jsm');
 
 function toggle_debug() {
   do_test_pending();
 
   function Wrapper() {
     this.init();
   }
   Wrapper.prototype = {
     QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
 
     observe: function observe(aSubject, aTopic, aData) {
       if (aTopic === "nsPref:changed") {
         // race condition?
-        do_check_eq(logger._enabled, true);
+        do_check_eq(Logger._debug, true);
         do_test_finished();
         run_next_test();
       }
     },
 
     init: function() {
       Services.prefs.addObserver('toolkit.identity.debug', this, false);
     }
   };
 
   var wrapper = new Wrapper();
   Services.prefs.setBoolPref('toolkit.identity.debug', true);
 }
 
 // test that things don't break
 
+function logAlias(...args) {
+  Logger.log.apply(Logger, ["log alias"].concat(args));
+}
+function reportErrorAlias(...args) {
+  Logger.reportError.apply(Logger, ["report error alias"].concat(args));
+}
+
 function test_log() {
-  logger.log("log test", "I like pie");
+  Logger.log("log test", "I like pie");
   do_test_finished();
   run_next_test();
 }
 
-function test_warning() {
-  logger.warning("similar log test", "We are still out of pies!!!");
+function test_reportError() {
+  Logger.reportError("log test", "We are out of pies!!!");
   do_test_finished();
   run_next_test();
 }
 
-function test_error() {
-  logger.error("My head a splode");
+function test_wrappers() {
+  logAlias("I like potatoes");
   do_test_finished();
-  run_next_test();
+  reportErrorAlias("Too much red bull");
 }
 
-
 let TESTS = [
 // XXX fix me 
 //    toggle_debug,
     test_log,
-    test_warning,
-    test_error
+    test_reportError,
+    test_wrappers
 ];
 
 TESTS.forEach(add_test);
 
 function run_test() {
   run_next_test();
-}
-
+}
\ No newline at end of file
--- a/toolkit/identity/tests/unit/test_minimalidentity.js
+++ b/toolkit/identity/tests/unit/test_minimalidentity.js
@@ -1,14 +1,20 @@
 "use strict";
 
 XPCOMUtils.defineLazyModuleGetter(this, "MinimalIDService",
                                   "resource://gre/modules/identity/MinimalIdentity.jsm",
                                   "IdentityService");
 
+Cu.import("resource://gre/modules/identity/LogUtils.jsm");
+
+function log(...aMessageArgs) {
+  Logger.log.apply(Logger, ["test_minimalidentity"].concat(aMessageArgs));
+}
+
 function test_overall() {
   do_check_neq(MinimalIDService, null);
   run_next_test();
 }
 
 function test_mock_doc() {
   do_test_pending();
   let mockedDoc = mock_doc(null, TEST_URL, function(action, params) {