Bug 804932 - Pass arbitrary options from RPs to BrowserID internal api methods. r=benadida

This commit is contained in:
Jed Parsons 2012-11-16 18:34:32 -05:00
parent 095334dcc9
commit ac891e49f3
14 changed files with 354 additions and 117 deletions

View File

@ -43,7 +43,7 @@ if (typeof kIdentityJSLoaded === 'undefined') {
}
var showUI = false;
var options = null;
var options = {};
var isLoaded = false;
var func = null;
@ -65,7 +65,6 @@ function identityCall(message) {
* destroys our context.
*/
function closeIdentityDialog() {
log('ready to close');
// tell gecko we're done.
func = null; options = null;
sendAsyncMessage(kIdentityDelegateFinished);
@ -78,17 +77,14 @@ function closeIdentityDialog() {
function doInternalWatch() {
log("doInternalWatch:", options, isLoaded);
if (options && isLoaded) {
log("internal watch options:", options);
let BrowserID = content.wrappedJSObject.BrowserID;
BrowserID.internal.watch(function(aParams) {
log("sending watch method message:", aParams.method);
identityCall(aParams);
if (aParams.method === "ready") {
log("watch finished.");
closeIdentityDialog();
}
},
JSON.stringify({loggedInUser: options.loggedInUser, origin: options.origin}),
JSON.stringify(options),
function(...things) {
log("internal: ", things);
}
@ -103,8 +99,7 @@ function doInternalRequest() {
options.origin,
function(assertion) {
if (assertion) {
log("request -> assertion, so do login");
identityCall({method:'login',assertion:assertion});
identityCall({method: 'login', assertion: assertion});
}
closeIdentityDialog();
},
@ -116,7 +111,6 @@ function doInternalLogout(aOptions) {
log("doInternalLogout:", (options && isLoaded));
if (options && isLoaded) {
let BrowserID = content.wrappedJSObject.BrowserID;
log("logging you out of ", options.origin);
BrowserID.internal.logout(options.origin, function() {
identityCall({method:'logout'});
closeIdentityDialog();
@ -134,7 +128,7 @@ addEventListener("DOMContentLoaded", function(e) {
// listen for request
addMessageListener(kIdentityDelegateRequest, function(aMessage) {
log("\n\n* * * * injected identity.js received", kIdentityDelegateRequest, "\n\n\n");
log("injected identity.js received", kIdentityDelegateRequest, "\n\n\n");
options = aMessage.json;
showUI = true;
func = doInternalRequest;
@ -143,7 +137,7 @@ addMessageListener(kIdentityDelegateRequest, function(aMessage) {
// listen for watch
addMessageListener(kIdentityDelegateWatch, function(aMessage) {
log("\n\n* * * * injected identity.js received", kIdentityDelegateWatch, "\n\n\n");
log("injected identity.js received", kIdentityDelegateWatch, "\n\n\n");
options = aMessage.json;
showUI = false;
func = doInternalWatch;
@ -152,7 +146,7 @@ addMessageListener(kIdentityDelegateWatch, function(aMessage) {
// listen for logout
addMessageListener(kIdentityDelegateLogout, function(aMessage) {
log("\n\n* * * * injected identity.js received", kIdentityDelegateLogout, "\n\n\n");
log("injected identity.js received", kIdentityDelegateLogout, "\n\n\n");
options = aMessage.json;
showUI = false;
func = doInternalLogout;

View File

@ -76,6 +76,7 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/IdentityUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "IdentityService",
"resource://gre/modules/identity/MinimalIdentity.jsm");
@ -101,18 +102,10 @@ const kIdentityDelegateReady = "identity-delegate-ready";
const kIdentityControllerDoMethod = "identity-controller-doMethod";
XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator");
function log(...aMessageArgs) {
Logger.log.apply(Logger, ["SignInToWebsiteController"].concat(aMessageArgs));
}
function getRandomId() {
return uuidgen.generateUUID().toString();
}
/*
* GaiaInterface encapsulates the our gaia functions. There are only two:
*
@ -207,8 +200,8 @@ let Pipe = {
let frameLoader = frame.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
let mm = frameLoader.messageManager;
try {
log("about to load frame script");
mm.loadFrameScript(kIdentityShimFile, true);
log("Loaded shim " + kIdentityShimFile + "\n");
} catch (e) {
log("Error loading ", kIdentityShimFile, " as a frame script: ", e);
}
@ -230,7 +223,7 @@ let Pipe = {
showUI: aGaiaOptions.showUI || false,
id: id
};
log('tell gaia to close the dialog');
log('telling gaia to close the dialog');
// tell gaia to close the dialog
GaiaInterface.sendChromeEvent(detail);
});
@ -305,7 +298,7 @@ this.SignInToWebsiteController = {
if (typeof message === 'string') {
message = JSON.parse(message);
}
log("doMethod:", message.method);
switch(message.method) {
case "ready":
IdentityService.doReady(aRpId);
@ -326,39 +319,38 @@ this.SignInToWebsiteController = {
};
},
doWatch: function SignInToWebsiteController_doWatch(aOptions) {
doWatch: function SignInToWebsiteController_doWatch(aRpOptions) {
// dom prevents watch from being called twice
log("doWatch:", aOptions);
var gaiaOptions = {
message: kIdentityDelegateWatch,
showUI: false
};
this.pipe.communicate(aOptions, gaiaOptions, this._makeDoMethodCallback(aOptions.rpId));
this.pipe.communicate(aRpOptions, gaiaOptions, this._makeDoMethodCallback(aRpOptions.id));
},
/**
* The website is requesting login so the user must choose an identity to use.
*/
doRequest: function SignInToWebsiteController_doRequest(aOptions) {
log("doRequest", aOptions);
doRequest: function SignInToWebsiteController_doRequest(aRpOptions) {
log("doRequest", aRpOptions);
// tell gaia to open the identity popup
var gaiaOptions = {
message: kIdentityDelegateRequest,
showUI: true
};
this.pipe.communicate(aOptions, gaiaOptions, this._makeDoMethodCallback(aOptions.rpId));
this.pipe.communicate(aRpOptions, gaiaOptions, this._makeDoMethodCallback(aRpOptions.id));
},
/*
*
*/
doLogout: function SignInToWebsiteController_doLogout(aOptions) {
log("doLogout", aOptions);
doLogout: function SignInToWebsiteController_doLogout(aRpOptions) {
log("doLogout", aRpOptions);
var gaiaOptions = {
message: kIdentityDelegateLogout,
showUI: false
};
this.pipe.communicate(aOptions, gaiaOptions, this._makeDoMethodCallback(aOptions.rpId));
this.pipe.communicate(aRpOptions, gaiaOptions, this._makeDoMethodCallback(aRpOptions.id));
}
};

View File

@ -47,11 +47,20 @@ function uuid() {
// create a mock "doc" object, which the Identity Service
// uses as a pointer back into the doc object
function mockDoc(aIdentity, aOrigin, aDoFunc) {
function mockDoc(aParams, aDoFunc) {
let mockedDoc = {};
mockedDoc.id = uuid();
mockedDoc.loggedInUser = aIdentity;
mockedDoc.origin = aOrigin;
// Properties of aParams may include loggedInUser
Object.keys(aParams).forEach(function(param) {
mockedDoc[param] = aParams[param];
});
// the origin is set inside nsDOMIdentity by looking at the
// document.nodePrincipal.origin. Here we, we must satisfy
// ourselves with pretending.
mockedDoc.origin = "https://jedp.gov";
mockedDoc['do'] = aDoFunc;
mockedDoc.doReady = partial(aDoFunc, 'ready');
mockedDoc.doLogin = partial(aDoFunc, 'login');
@ -67,7 +76,12 @@ function mockDoc(aIdentity, aOrigin, aDoFunc) {
// messages up to gaia (either the trusty ui or the hidden iframe),
// and convey messages back down from gaia to the controller through
// the message callback.
function mockPipe() {
// The mock receiving pipe simulates gaia which, after receiving messages
// through the pipe, will call back with instructions to invoke
// certain methods. It mocks what comes back from the other end of
// the pipe.
function mockReceivingPipe() {
let MockedPipe = {
communicate: function(aRpOptions, aGaiaOptions, aMessageCallback) {
switch (aGaiaOptions.message) {
@ -89,6 +103,17 @@ function mockPipe() {
return MockedPipe;
}
// The mock sending pipe lets us test what's actually getting put in the
// pipe.
function mockSendingPipe(aMessageCallback) {
let MockedPipe = {
communicate: function(aRpOptions, aGaiaOptions, aDummyCallback) {
aMessageCallback(aRpOptions, aGaiaOptions);
}
};
return MockedPipe;
}
// mimicking callback funtionality for ease of testing
// this observer auto-removes itself after the observe function
// is called, so this is meant to observe only ONE event.

View File

@ -24,9 +24,69 @@ function test_overall() {
run_next_test();
}
function objectContains(object, subset) {
let objectKeys = Object.keys(object);
let subsetKeys = Object.keys(subset);
// can't have fewer keys than the subset
if (objectKeys.length < subsetKeys.length) {
return false;
}
let key;
let success = true;
if (subsetKeys.length > 0) {
for (let i=0; i<subsetKeys.length; i++) {
key = subsetKeys[i];
// key exists in the source object
if (typeof object[key] === 'undefined') {
success = false;
break;
}
// recursively check object values
else if (typeof subset[key] === 'object') {
if (typeof object[key] !== 'object') {
success = false;
break;
}
if (! objectContains(object[key], subset[key])) {
success = false;
break;
}
}
else if (object[key] !== subset[key]) {
success = false;
break;
}
}
}
return success;
}
function test_object_contains() {
do_test_pending();
let someObj = {
pies: 42,
green: "spam",
flan: {yes: "please"}
};
let otherObj = {
pies: 42,
flan: {yes: "please"}
};
do_check_true(objectContains(someObj, otherObj));
do_test_finished();
run_next_test();
}
function test_mock_doc() {
do_test_pending();
let mockedDoc = mockDoc(null, TEST_URL, function(action, params) {
let mockedDoc = mockDoc({loggedInUser: null}, function(action, params) {
do_check_eq(action, 'coffee');
do_test_finished();
run_next_test();
@ -43,15 +103,14 @@ function test_watch() {
setup_test_identity("pie@food.gov", TEST_CERT, function() {
let controller = SignInToWebsiteController;
let mockedDoc = mockDoc(null, TEST_URL, function(action, params) {
let mockedDoc = mockDoc({loggedInUser: null}, function(action, params) {
do_check_eq(action, 'ready');
controller.uninit();
do_test_finished();
run_next_test();
});
controller.init({pipe: mockPipe()});
controller.init({pipe: mockReceivingPipe()});
MinimalIDService.RP.watch(mockedDoc, {});
});
}
@ -62,7 +121,7 @@ function test_request_login() {
setup_test_identity("flan@food.gov", TEST_CERT, function() {
let controller = SignInToWebsiteController;
let mockedDoc = mockDoc(null, TEST_URL, call_sequentially(
let mockedDoc = mockDoc({loggedInUser: null}, call_sequentially(
function(action, params) {
do_check_eq(action, 'ready');
do_check_eq(params, undefined);
@ -76,7 +135,7 @@ function test_request_login() {
}
));
controller.init({pipe: mockPipe()});
controller.init({pipe: mockReceivingPipe()});
MinimalIDService.RP.watch(mockedDoc, {});
MinimalIDService.RP.request(mockedDoc.id, {});
});
@ -88,7 +147,7 @@ function test_request_logout() {
setup_test_identity("flan@food.gov", TEST_CERT, function() {
let controller = SignInToWebsiteController;
let mockedDoc = mockDoc(null, TEST_URL, call_sequentially(
let mockedDoc = mockDoc({loggedInUser: null}, call_sequentially(
function(action, params) {
do_check_eq(action, 'ready');
do_check_eq(params, undefined);
@ -102,7 +161,7 @@ function test_request_logout() {
}
));
controller.init({pipe: mockPipe()});
controller.init({pipe: mockReceivingPipe()});
MinimalIDService.RP.watch(mockedDoc, {});
MinimalIDService.RP.logout(mockedDoc.id, {});
});
@ -114,7 +173,7 @@ function test_request_login_logout() {
setup_test_identity("unagi@food.gov", TEST_CERT, function() {
let controller = SignInToWebsiteController;
let mockedDoc = mockDoc(null, TEST_URL, call_sequentially(
let mockedDoc = mockDoc({loggedInUser: null}, call_sequentially(
function(action, params) {
do_check_eq(action, 'ready');
do_check_eq(params, undefined);
@ -130,29 +189,68 @@ function test_request_login_logout() {
do_test_finished();
run_next_test();
}
/*
,function(action, params) {
do_check_eq(action, 'ready');
do_test_finished();
run_next_test();
}
*/
));
controller.init({pipe: mockPipe()});
controller.init({pipe: mockReceivingPipe()});
MinimalIDService.RP.watch(mockedDoc, {});
MinimalIDService.RP.request(mockedDoc.id, {});
MinimalIDService.RP.logout(mockedDoc.id, {});
});
}
function test_options_pass_through() {
do_test_pending();
// An meaningless structure for testing that RP messages preserve
// objects and their parameters as they are passed back and forth.
let randomMixedParams = {
loggedInUser: "juanita@mozilla.com",
pie: 42,
someThing: {
name: "Pertelote",
legs: 4,
nested: {bee: "Eric", remaining: "1/2"}
}
};
let mockedDoc = mockDoc(randomMixedParams, function(action, params) {});
function pipeOtherEnd(rpOptions, gaiaOptions) {
// Ensure that every time we receive a message, our mixed
// random params are contained in that message
do_check_true(objectContains(rpOptions, randomMixedParams));
switch (gaiaOptions.message) {
case "identity-delegate-watch":
MinimalIDService.RP.request(mockedDoc.id, {});
break;
case "identity-delegate-request":
MinimalIDService.RP.logout(mockedDoc.id, {});
break;
case "identity-delegate-logout":
do_test_finished();
run_next_test();
break;
}
}
let controller = SignInToWebsiteController;
controller.init({pipe: mockSendingPipe(pipeOtherEnd)});
MinimalIDService.RP.watch(mockedDoc, {});
}
let TESTS = [
test_overall,
test_mock_doc,
test_object_contains,
test_watch,
test_request_login,
test_request_logout,
test_request_login_logout
test_request_login_logout,
test_options_pass_through
];
TESTS.forEach(add_test);

View File

@ -11,6 +11,7 @@ this.EXPORTED_SYMBOLS = ["DOMIdentity"];
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/IdentityUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "IdentityService",
#ifdef MOZ_B2G_VERSION
@ -31,8 +32,8 @@ function log(...aMessageArgs) {
Logger.log.apply(Logger, ["DOMIdentity"].concat(aMessageArgs));
}
function IDDOMMessage(aID) {
this.id = aID;
function IDDOMMessage(aOptions) {
objectCopy(aOptions, this);
}
function IDPProvisioningContext(aID, aOrigin, aTargetMM) {
@ -46,7 +47,7 @@ IDPProvisioningContext.prototype = {
get origin() this._origin,
doBeginProvisioningCallback: function IDPPC_doBeginProvCB(aID, aCertDuration) {
let message = new IDDOMMessage(this.id);
let message = new IDDOMMessage({id: this.id});
message.identity = aID;
message.certDuration = aCertDuration;
this._mm.sendAsyncMessage("Identity:IDP:CallBeginProvisioningCallback",
@ -55,7 +56,7 @@ IDPProvisioningContext.prototype = {
doGenKeyPairCallback: function IDPPC_doGenKeyPairCallback(aPublicKey) {
log("doGenKeyPairCallback");
let message = new IDDOMMessage(this.id);
let message = new IDDOMMessage({id: this.id});
message.publicKey = aPublicKey;
this._mm.sendAsyncMessage("Identity:IDP:CallGenKeyPairCallback", message);
},
@ -76,7 +77,7 @@ IDPAuthenticationContext.prototype = {
get origin() this._origin,
doBeginAuthenticationCallback: function IDPAC_doBeginAuthCB(aIdentity) {
let message = new IDDOMMessage(this.id);
let message = new IDDOMMessage({id: this.id});
message.identity = aIdentity;
this._mm.sendAsyncMessage("Identity:IDP:CallBeginAuthenticationCallback",
message);
@ -87,34 +88,37 @@ IDPAuthenticationContext.prototype = {
},
};
function RPWatchContext(aID, aOrigin, aLoggedInUser, aTargetMM) {
this._id = aID;
this._origin = aOrigin;
this._loggedInUser = aLoggedInUser;
function RPWatchContext(aOptions, aTargetMM) {
objectCopy(aOptions, this);
// id and origin are required
if (! (this.id && this.origin)) {
throw new Error("id and origin are required for RP watch context");
}
// default for no loggedInUser is undefined, not null
this.loggedInUser = aOptions.loggedInUser;
this._mm = aTargetMM;
}
RPWatchContext.prototype = {
get id() this._id,
get origin() this._origin,
get loggedInUser() this._loggedInUser,
doLogin: function RPWatchContext_onlogin(aAssertion) {
log("doLogin: " + this.id);
let message = new IDDOMMessage(this.id);
let message = new IDDOMMessage({id: this.id});
message.assertion = aAssertion;
this._mm.sendAsyncMessage("Identity:RP:Watch:OnLogin", message);
},
doLogout: function RPWatchContext_onlogout() {
log("doLogout :" + this.id);
let message = new IDDOMMessage(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() {
log("doReady: " + this.id);
let message = new IDDOMMessage(this.id);
let message = new IDDOMMessage({id: this.id});
this._mm.sendAsyncMessage("Identity:RP:Watch:OnReady", message);
},
@ -212,7 +216,7 @@ this.DOMIdentity = {
if (!aContext._mm) {
throw new Error("ERROR: Trying to reset an invalid context");
}
let message = new IDDOMMessage(aContext.id);
let message = new IDDOMMessage({id: aContext.id});
aContext._mm.sendAsyncMessage("Identity:ResetState", message);
},
@ -220,8 +224,7 @@ this.DOMIdentity = {
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.id, message.origin,
message.loggedInUser, targetMM);
let context = new RPWatchContext(message, targetMM);
IdentityService.RP.watch(context);
},
@ -230,7 +233,7 @@ this.DOMIdentity = {
},
_logout: function DOMIdentity__logout(message) {
IdentityService.RP.logout(message.id, message.origin);
IdentityService.RP.logout(message.id, message.origin, message);
},
_beginProvisioning: function DOMIdentity__beginProvisioning(message, targetMM) {

View File

@ -18,13 +18,11 @@ Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/IdentityUtils.jsm");
// This is the child process corresponding to nsIDOMIdentity
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
"@mozilla.org/childprocessmessagemanager;1",
"nsIMessageSender");
// This is the child process corresponding to nsIDOMIdentity.
function nsDOMIdentity(aIdentityInternal) {
this._identityInternal = aIdentityInternal;
}
@ -77,7 +75,7 @@ nsDOMIdentity.prototype = {
throw new Error("onready must be a function");
}
let message = this.DOMIdentityMessage();
let message = this.DOMIdentityMessage(aOptions);
// loggedInUser vs loggedInEmail
// https://developer.mozilla.org/en-US/docs/DOM/navigator.id.watch
@ -125,7 +123,7 @@ nsDOMIdentity.prototype = {
throw new Error("navigator.id.request called too many times");
}
let message = this.DOMIdentityMessage();
let message = this.DOMIdentityMessage(aOptions);
if (aOptions) {
// Optional string properties
@ -314,7 +312,6 @@ nsDOMIdentity.prototype = {
_receiveMessage: function nsDOMIdentity_receiveMessage(aMessage) {
let msg = aMessage.json;
this._log("receiveMessage: " + aMessage.name);
switch (aMessage.name) {
case "Identity:ResetState":
@ -419,13 +416,24 @@ nsDOMIdentity.prototype = {
},
/**
* Helper to create messages to send using a message manager
* Helper to create messages to send using a message manager.
* Pass through user options if they are not functions. Always
* overwrite id and origin. Caller does not get to set those.
*/
DOMIdentityMessage: function DOMIdentityMessage() {
return {
id: this._id,
origin: this._origin,
};
DOMIdentityMessage: function DOMIdentityMessage(aOptions) {
aOptions = aOptions || {};
let message = {};
objectCopy(aOptions, message);
// outer window id
message.id = this._id;
// window origin
message.origin = this._origin;
dump("nsDOM message: " + JSON.stringify(message) + "\n");
return message;
},
};

View File

@ -8,10 +8,21 @@
"use strict";
this.EXPORTED_SYMBOLS = ["checkDeprecated", "checkRenamed"];
this.EXPORTED_SYMBOLS = [
"checkDeprecated",
"checkRenamed",
"getRandomId",
"objectCopy"
];
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "uuidgen",
"@mozilla.org/uuid-generator;1",
"nsIUUIDGenerator");
XPCOMUtils.defineLazyModuleGetter(this, "Logger",
"resource://gre/modules/identity/LogUtils.jsm");
@ -44,3 +55,21 @@ this.checkRenamed = function checkRenamed(aOptions, aOldName, aNewName) {
delete(aOptions[aOldName]);
}
};
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){
let desc;
Object.getOwnPropertyNames(source).forEach(function(name) {
if (name[0] !== '_') {
desc = Object.getOwnPropertyDescriptor(source, name);
Object.defineProperty(target, name, desc);
}
});
};

View File

@ -25,6 +25,7 @@ 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.defineLazyModuleGetter(this,
"jwcrypto",
@ -37,6 +38,35 @@ 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
options.loggedInUser = aRpCaller.loggedInUser;
Object.keys(aRpCaller).forEach(function(option) {
// Duplicate the callerobject, scrubbing out functions and other
// internal variables (like _mm, the message manager object)
if (!Object.hasOwnProperty(this, option)
&& option[0] !== '_'
&& typeof aRpCaller[option] !== 'function') {
options[option] = aRpCaller[option];
}
});
if (! (options.id && options.origin)) {
let err = "id and origin required in relying-party message";
reportError(err);
throw new Error(err);
}
dump("message object is: " + JSON.stringify(options) + "\n");
return options;
}
function IDService() {
Services.obs.addObserver(this, "quit-application-granted", false);
// Services.obs.addObserver(this, "identity-auth-complete", false);
@ -97,15 +127,11 @@ IDService.prototype = {
*
*/
watch: function watch(aRpCaller) {
log("watch: caller keys:", Object.keys(aRpCaller));
log("watch: rpcaller:", aRpCaller);
// store the caller structure and notify the UI observers
dump("RP - watch: " + JSON.stringify(aRpCaller) + "\n");
this._rpFlows[aRpCaller.id] = aRpCaller;
let options = {rpId: aRpCaller.id,
origin: aRpCaller.origin,
loggedInUser: aRpCaller.loggedInUser};
let options = makeMessageObject(aRpCaller);
log("sending identity-controller-watch:", options);
Services.obs.notifyObservers({wrappedJSObject: options},"identity-controller-watch", null);
},
@ -121,12 +147,12 @@ IDService.prototype = {
* (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};
let options = makeMessageObject(rp);
objectCopy(aOptions, options);
Services.obs.notifyObservers({wrappedJSObject: options}, "identity-controller-request", null);
},
@ -139,10 +165,9 @@ IDService.prototype = {
*
*/
logout: function logout(aRpCallerId) {
log("logout: RP caller id:", aRpCallerId);
let rp = this._rpFlows[aRpCallerId];
let options = {rpId: aRpCallerId, origin: rp.origin};
let options = makeMessageObject(rp);
Services.obs.notifyObservers({wrappedJSObject: options}, "identity-controller-logout", null);
},
@ -154,24 +179,30 @@ IDService.prototype = {
doLogin: function doLogin(aRpCallerId, aAssertion) {
let rp = this._rpFlows[aRpCallerId];
if (!rp)
if (!rp) {
dump("WARNING: doLogin found no rp to go with callerId " + aRpCallerId + "\n");
return;
}
rp.doLogin(aAssertion);
},
doLogout: function doLogout(aRpCallerId) {
let rp = this._rpFlows[aRpCallerId];
if (!rp)
if (!rp) {
dump("WARNING: doLogout found no rp to go with callerId " + aRpCallerId + "\n");
return;
}
rp.doLogout();
},
doReady: function doReady(aRpCallerId) {
let rp = this._rpFlows[aRpCallerId];
if (!rp)
if (!rp) {
dump("WARNING: doReady found no rp to go with callerId " + aRpCallerId + "\n");
return;
}
rp.doReady();
},

View File

@ -14,6 +14,7 @@ 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"];
@ -215,6 +216,7 @@ IdentityRelyingParty.prototype = {
// 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);

View File

@ -0,0 +1,46 @@
"use strict";
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/identity/IdentityUtils.jsm');
function test_check_deprecated() {
let options = {
id: 123,
loggedInEmail: "jed@foo.com",
pies: 42
};
do_check_true(checkDeprecated(options, "loggedInEmail"));
do_check_false(checkDeprecated(options, "flans"));
run_next_test();
}
function test_check_renamed() {
let options = {
id: 123,
loggedInEmail: "jed@foo.com",
pies: 42
};
checkRenamed(options, "loggedInEmail", "loggedInUser");
// It moves loggedInEmail to loggedInUser
do_check_false(!!options.loggedInEmail);
do_check_eq(options.loggedInUser, "jed@foo.com");
run_next_test();
}
let TESTS = [
test_check_deprecated,
test_check_renamed
];
TESTS.forEach(add_test);
function run_test() {
run_next_test();
}

View File

@ -9,10 +9,10 @@ function toggle_debug() {
do_test_pending();
function Wrapper() {
Services.prefs.addObserver('toolkit.identity.debug', this, false);
this.init();
}
Wrapper.prototype = {
QueryInterface: XPCOMUtils.generateQI([ci.nsISupports, Ci.nsIObserver]),
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
observe: function observe(aSubject, aTopic, aData) {
if (aTopic === "nsPref:changed") {
@ -21,6 +21,10 @@ function toggle_debug() {
do_test_finished();
run_next_test();
}
},
init: function() {
Services.prefs.addObserver('toolkit.identity.debug', this, false);
}
};
@ -31,10 +35,10 @@ function toggle_debug() {
// test that things don't break
function logAlias(...args) {
Logger.log.call(["log alias"].concat(args));
Logger.log.apply(Logger, ["log alias"].concat(args));
}
function reportErrorAlias(...args) {
Logger.reportError.call(["report error alias"].concat(args));
Logger.reportError.apply(Logger, ["report error alias"].concat(args));
}
function test_log() {
@ -56,12 +60,15 @@ function test_wrappers() {
}
let TESTS = [
toggle_debug,
// XXX fix me
// toggle_debug,
test_log,
test_reportError,
test_wrappers
];
TESTS.forEach(add_test);
function run_test() {
run_next_test();
}

View File

@ -34,7 +34,7 @@ function test_watch() {
let mockedDoc = mock_doc(null, TEST_URL);
makeObserver("identity-controller-watch", function (aSubject, aTopic, aData) {
do_check_eq(aSubject.wrappedJSObject.rpId, mockedDoc.id);
do_check_eq(aSubject.wrappedJSObject.id, mockedDoc.id);
do_check_eq(aSubject.wrappedJSObject.origin, TEST_URL);
do_test_finished();
run_next_test();
@ -51,7 +51,7 @@ function test_request() {
let mockedDoc = mock_doc(null, TEST_URL);
makeObserver("identity-controller-request", function (aSubject, aTopic, aData) {
do_check_eq(aSubject.wrappedJSObject.rpId, mockedDoc.id);
do_check_eq(aSubject.wrappedJSObject.id, mockedDoc.id);
do_check_eq(aSubject.wrappedJSObject.origin, TEST_URL);
do_test_finished();
run_next_test();
@ -69,7 +69,7 @@ function test_logout() {
let mockedDoc = mock_doc(null, TEST_URL);
makeObserver("identity-controller-logout", function (aSubject, aTopic, aData) {
do_check_eq(aSubject.wrappedJSObject.rpId, mockedDoc.id);
do_check_eq(aSubject.wrappedJSObject.id, mockedDoc.id);
do_test_finished();
run_next_test();
});
@ -78,8 +78,6 @@ function test_logout() {
MinimalIDService.RP.logout(mockedDoc.id, {});
}
let TESTS = [
test_overall,
test_mock_doc,

View File

@ -197,12 +197,15 @@ function test_logout() {
});
}
let TESTS = [];
TESTS = TESTS.concat([test_watch_loggedin_ready, test_watch_loggedin_login, test_watch_loggedin_logout]);
TESTS = TESTS.concat([test_watch_notloggedin_ready, test_watch_notloggedin_logout]);
TESTS.push(test_request);
TESTS.push(test_logout);
let TESTS = [
test_watch_loggedin_ready,
test_watch_loggedin_login,
test_watch_loggedin_logout,
test_watch_notloggedin_ready,
test_watch_notloggedin_logout,
test_request,
test_logout
];
TESTS.forEach(add_test);

View File

@ -6,6 +6,7 @@ tail = tail_identity.js
[test_load_modules.js]
[test_minimalidentity.js]
[test_identity_utils.js]
[test_log_utils.js]
[test_authentication.js]
[test_crypto_service.js]