Creating a Login Manager storage module

The Login Manager manages and stores user passwords. Extensions can replace the built-in password storage with their own implementation. This can be useful if you want to integrate a gecko application's password management with an existing password management system, or use your own password storage format or database. So for example, on KDE is is desirable to fully employ the KDE wallet manager, rather than any secondary replacements of KDEwallet.

If you just want to use the Login Manager in your extensions, refer to the article Using nsILoginManager.

Overriding the built-in Login Manager storage consists of two tasks:

  1. Implement the nsILoginManagerStorage interface.
  2. Register that interface in a specific category.
Some work has already been done to integrate the Login Manager with the Mac OS X keychain (bug 106400) and Gnome Keyring Manager (bug 309807). You should start with the existing code if you want to implement that in your extension.
To see some debugging output in the console set signon.debug to true using about:config.

Sample JavaScript implementation

The following code snippet is a JavaScript component that implements a dummy nsILoginManagerStorage interface. See How_to_Build_an_XPCOM_Component_in_Javascript for more details about JavaScript components.

const Cc = Components.classes;
const Ci = Components.interfaces;

Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");

function SampleLoginManagerStorage() {}
SampleLoginManagerStorage.prototype = {
  classDescription: "Sample nsILoginManagerStorage implementation",
  contractID: "@example.com/login-manager/storage/sample;1",
  classID: Components.ID("{364a118c-747a-4f6d-ac63-2d2998e5a5c1}"),
  QueryInterface: XPCOMUtils.generateQI([Ci.nsILoginManagerStorage]),

  // This registers the category for overriding the built-in nsILoginManagerStorage
  _xpcom_categories: [
    {
      category: "login-manager-storage",
      entry: "nsILoginManagerStorage"
    }
  ],


 // Console logging service, used for debugging.
  __logService : null,
  get _logService() {
    if (!this.__logService)
      this.__logService = Cc["@mozilla.org/consoleservice;1"].
                            getService(Ci.nsIConsoleService);
    return this.__logService;
  },
  log: function (message) {
    dump("SampleLoginManager: " + message + "\n");
    this._logService.logStringMessage("SampleLoginManager: " + message);
  },
  // Logs function name and arguments for debugging
  stub: function(arguments) {
    var args = [];
    for (let i = 0; i < arguments.length; i++)
      args.push(arguments[i])
    this.log("Called " + arguments.callee.name + "(" + args.join(",") + ")");
  },

  init: function SLMS_init() {
    this.stub(arguments);
  },
  initWithFile: function SLMS_initWithFile(aInputFile, aOutputFile) {
    this.stub(arguments);
  },
  addLogin: function SLMS_addLogin(login) {
    this.stub(arguments);
  },
  removeLogin: function SLMS_removeLogin(login) {
    this.stub(arguments);
  },
  modifyLogin: function SLMS_modifyLogin(oldLogin, newLogin) {
    this.stub(arguments);
  },
  getAllLogins: function SLMS_getAllLogins(count) {
    this.stub(arguments);
  },
  removeAllLogins: function SLMS_removeAllLogins() {
    this.stub(arguments);
  },
  getAllDisabledHosts: function SLMS_getAllDisabledHosts(count) {
    this.stub(arguments);
  },
  getLoginSavingEnabled: function SLMS_getLoginSavingEnabled(hostname) {
    this.stub(arguments);
  },
  setLoginSavingEnabled: function SLMS_setLoginSavingEnabled(hostname, enabled) {
    this.stub(arguments);
  },
  findLogins: function SLMS_findLogins(count, hostname, formSubmitURL, httpRealm) {
    this.stub(arguments);
  },
  countLogins: function SLMS_countLogins(aHostname, aFormSubmitURL, aHttpRealm) {
    this.stub(arguments);
  }
};

function NSGetModule(compMgr, fileSpec)
  XPCOMUtils.generateModule([SampleLoginManagerStorage]);

Sample C++ Implementation

bug 309807 contains a complete example. The category registration looks like this:

  nsCOMPtr<nsICategoryManager> cat =
      do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
  NS_ENSURE_STATE(cat);

  cat->AddCategoryEntry("login-manager-storage", "nsILoginManagerStorage",
                        kYourContractID, PR_TRUE, PR_TRUE, nsnull);

Don't forget to unregister the category on unload.