summaryrefslogtreecommitdiff
path: root/toolkit/identity/RelyingParty.jsm
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/identity/RelyingParty.jsm')
-rw-r--r--toolkit/identity/RelyingParty.jsm367
1 files changed, 0 insertions, 367 deletions
diff --git a/toolkit/identity/RelyingParty.jsm b/toolkit/identity/RelyingParty.jsm
deleted file mode 100644
index 5996383ca1..0000000000
--- a/toolkit/identity/RelyingParty.jsm
+++ /dev/null
@@ -1,367 +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";
-
-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");
-
-this.EXPORTED_SYMBOLS = ["RelyingParty"];
-
-XPCOMUtils.defineLazyModuleGetter(this, "objectCopy",
- "resource://gre/modules/identity/IdentityUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this,
- "jwcrypto",
- "resource://gre/modules/identity/jwcrypto.jsm");
-
-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();
-}
-
-IdentityRelyingParty.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;
-
- }
- },
-
- reset: function RP_reset() {
- // Forget all documents that call in. (These are sometimes
- // referred to as callers.)
- this._rpFlows = {};
- },
-
- shutdown: function RP_shutdown() {
- this.reset();
- Services.obs.removeObserver(this, "quit-application-granted");
- },
-
- /**
- * 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)
- * - origin (string)
- *
- * and a bunch of callbacks
- * - doReady()
- * - doLogin()
- * - doLogout()
- * - doError()
- * - doCancel()
- *
- */
- watch: function watch(aRpCaller) {
- this._rpFlows[aRpCaller.id] = aRpCaller;
- let origin = aRpCaller.origin;
- let state = this._store.getLoginState(origin) || { isLoggedIn: false, email: null };
-
- 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:
- //
- // 1. the email is valid and unchanged: 'ready'
- // 2. the email is null: 'login'; 'ready'
- // 3. the email has changed: 'login'; 'ready'
- if (state.isLoggedIn) {
- if (state.email && aRpCaller.loggedInUser === state.email) {
- this._notifyLoginStateChanged(aRpCaller.id, state.email);
- return aRpCaller.doReady();
-
- } else if (aRpCaller.loggedInUser === null) {
- // Generate assertion for existing login
- let options = {loggedInUser: state.email, origin: origin};
- return this._doLogin(aRpCaller, options);
- }
- // A loggedInUser different from state.email has been specified.
- // Change login identity.
-
- let options = {loggedInUser: state.email, origin: origin};
- return this._doLogin(aRpCaller, options);
-
- // If the user is not logged in, there are two cases:
- //
- // 1. a logged in email was provided: 'ready'; 'logout'
- // 2. not logged in, no email given: 'ready';
-
- }
- if (aRpCaller.loggedInUser) {
- return this._doLogout(aRpCaller, {origin: origin});
- }
- return aRpCaller.doReady();
- },
-
- /**
- * A utility for watch() to set state and notify the dom
- * on login
- *
- * Note that this calls _getAssertion
- */
- _doLogin: function _doLogin(aRpCaller, aOptions, aAssertion) {
- 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) {
- 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) {
- 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();
- },
-
- /**
- * For use with login or logout, emit 'identity-login-state-changed'
- *
- * The notification will send the rp caller id in the properties,
- * and the email of the user in the message.
- *
- * @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) {
- log("_notifyLoginStateChanged: rpId:", aRpCallerId, "identity:", aIdentity);
-
- let options = {rpId: aRpCallerId};
- Services.obs.notifyObservers({wrappedJSObject: options},
- "identity-login-state-changed",
- aIdentity);
- },
-
- /**
- * 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 request(aRPId, aOptions) {
- 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
- let baseURI = Services.io.newURI(rp.origin, null, null);
- for (let optionName of ["privacyPolicy", "termsOfService"]) {
- if (aOptions[optionName]) {
- options[optionName] = baseURI.resolve(aOptions[optionName]);
- }
- }
-
- Services.obs.notifyObservers({wrappedJSObject: options}, "identity-request", null);
- },
-
- /**
- * 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) {
- log("logout: RP caller id:", aRpCallerId);
- let rp = this._rpFlows[aRpCallerId];
- if (rp && rp.origin) {
- let origin = rp.origin;
- log("logout: origin:", origin);
- this._doLogout(rp, {origin: origin});
- } else {
- 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;
- 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: [] };
- for (let id in this._store.getIdentities()) {
- rv.result.push(id);
- }
- let loginState = this._store.getLoginState(aOrigin);
- if (loginState && loginState.email)
- rv.lastUsed = loginState.email;
- return rv;
- },
-
- /**
- * Obtain a BrowserID assertion with the specified characteristics.
- *
- * @param aCallback
- * (Function) Callback to be called with (err, assertion) where 'err'
- * can be an Error or NULL, and 'assertion' can be NULL or a valid
- * BrowserID assertion. If no callback is provided, an exception is
- * thrown.
- *
- * @param aOptions
- * (Object) An object that may contain the following properties:
- *
- * "audience" : The audience for which the assertion is to be
- * 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);
- 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) {
- log("ERROR: _getAssertion:", err);
- }
- 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
- * with an error.
- *
- * @param aAudience
- * (string) web origin
- *
- * @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) {
- 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";
- log("ERROR: _generateAssertion:", errStr);
- aCallback(errStr);
- return;
- }
-
- let kp = id.keyPair;
-
- if (!kp) {
- let errStr = "Cannot generate an assertion without a keypair";
- 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 {
- log("Error: Couldn't delete provision flow ", aProvId, " for RP ", aRPId);
- }
- },
-
-};
-
-this.RelyingParty = new IdentityRelyingParty();