summaryrefslogtreecommitdiffstats
path: root/toolkit/identity/Identity.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/identity/Identity.jsm')
-rw-r--r--toolkit/identity/Identity.jsm309
1 files changed, 0 insertions, 309 deletions
diff --git a/toolkit/identity/Identity.jsm b/toolkit/identity/Identity.jsm
deleted file mode 100644
index a27b7c93d..000000000
--- a/toolkit/identity/Identity.jsm
+++ /dev/null
@@ -1,309 +0,0 @@
-/* -*- js-indent-level: 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 = ["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/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");
-
-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;
-}
-
-IDService.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
-
- observe: function observe(aSubject, aTopic, aData) {
- switch (aTopic) {
- 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;
- 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() {
- // Explicitly call reset() on our RP and IDP classes.
- // This is here to make testing easier. When the
- // quit-application-granted signal is emitted, reset() will be
- // 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() {
- log("shutdown");
- Services.obs.removeObserver(this, "identity-auth-complete");
- // try to prevent abort/crash during shutdown of mochitest-browser2...
- try {
- Services.obs.removeObserver(this, "quit-application-granted");
- } catch (e) {}
- },
-
- /**
- * 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;
- },
-
- /**
- * The UX wants to add a new identity
- * often followed by selectIdentity()
- *
- * @param aIdentity
- * (string) the email chosen for login
- */
- addIdentity: function addIdentity(aIdentity) {
- if (this._store.fetchIdentity(aIdentity) === null) {
- this._store.addIdentity(aIdentity, null, null);
- }
- },
-
- /**
- * The UX comes back and calls selectIdentity once the user has picked
- * an identity.
- *
- * @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) {
- 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) {
- 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
- };
- 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;
-
- }
- // Need to provision an identity first. Begin by discovering
- // the user's IdP.
- self._discoverIdentityProvider(aIdentity, function gotIDP(err, idpParams) {
- if (err) {
- rp.doError(err);
- return;
- }
-
- // The idpParams tell us where to go to provision and authenticate
- // the identity.
- self.IDP._provisionIdentity(aIdentity, idpParams, provId, function gotID(err, aProvId) {
-
- // Provision identity may have created a new provision flow
- // for us. To make it easier to relate provision flows with
- // RP callers, we cross index the two here.
- rp.provId = aProvId;
- self.IDP._provisionFlows[aProvId].rpId = aRPId;
-
- // At this point, we already have a cert. If the user is also
- // already authenticated with the IdP, then we can try again
- // to generate an assertion and login.
- if (err) {
- // 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);
- 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;
- }
-
- // Provisioning flows end when a certificate has been registered.
- // Thus IdentityProvider's registerCertificate() cleans up the
- // current provisioning flow. We only do this here on error.
- self.RP._generateAssertion(rp.origin, aIdentity, function gotAssertion(err, assertion) {
- if (err) {
- rp.doError(err);
- return;
- }
- self.RP._doLogin(rp, rpLoginOptions, assertion);
- self.RP._cleanUpProvisionFlow(aRPId, aProvId);
- return;
- });
- });
- });
- });
- },
-
- // 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) {
- aCallback("Could not parse email: " + aIdentity);
- return;
- }
- 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();