mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-17 20:57:30 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
7
toolkit/identity/tests/unit/.eslintrc.js
Normal file
7
toolkit/identity/tests/unit/.eslintrc.js
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"../../../../testing/xpcshell/xpcshell.eslintrc.js"
|
||||
]
|
||||
};
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"public-key": {"algorithm":"RS","n":"65718905405105134410187227495885391609221288015566078542117409373192106382993306537273677557482085204736975067567111831005921322991127165013340443563713385983456311886801211241492470711576322130577278575529202840052753612576061450560588102139907846854501252327551303482213505265853706269864950437458242988327","e":"65537"},
|
||||
"authentication": "/browserid/sign_in.html",
|
||||
"provisioning": "/browserid/provision.html"
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"public-key": {"algorithm":"RS","n":"65718905405105134410187227495885391609221288015566078542117409373192106382993306537273677557482085204736975067567111831005921322991127165013340443563713385983456311886801211241492470711576322130577278575529202840052753612576061450560588102139907846854501252327551303482213505265853706269864950437458242988327","e":"65537"},
|
||||
"authentication": "/browserid/sign_in.html",
|
||||
// missing "provisioning"
|
||||
}
|
||||
256
toolkit/identity/tests/unit/head_identity.js
Normal file
256
toolkit/identity/tests/unit/head_identity.js
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
var Cu = Components.utils;
|
||||
var Cr = Components.results;
|
||||
|
||||
Cu.import("resource://testing-common/httpd.js");
|
||||
|
||||
// XXX until bug 937114 is fixed
|
||||
Cu.importGlobalProperties(["atob"]);
|
||||
|
||||
// The following boilerplate makes sure that XPCOM calls
|
||||
// that use the profile directory work.
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto",
|
||||
"resource://gre/modules/identity/jwcrypto.jsm");
|
||||
|
||||
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_MESSAGE_MANAGER = "Mr McFeeley";
|
||||
const TEST_URL = "https://myfavoritebacon.com";
|
||||
const TEST_URL2 = "https://myfavoritebaconinacan.com";
|
||||
const TEST_USER = "user@mozilla.com";
|
||||
const TEST_PRIVKEY = "fake-privkey";
|
||||
const TEST_CERT = "fake-cert";
|
||||
const TEST_ASSERTION = "fake-assertion";
|
||||
const TEST_IDPPARAMS = {
|
||||
domain: "myfavoriteflan.com",
|
||||
authentication: "/foo/authenticate.html",
|
||||
provisioning: "/foo/provision.html"
|
||||
};
|
||||
|
||||
// The following are utility functions for Identity testing
|
||||
|
||||
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() {
|
||||
return fn.apply(this, args.concat(Array.prototype.slice.call(arguments)));
|
||||
};
|
||||
}
|
||||
|
||||
function uuid() {
|
||||
return uuidGenerator.generateUUID().toString();
|
||||
}
|
||||
|
||||
function base64UrlDecode(s) {
|
||||
s = s.replace(/-/g, "+");
|
||||
s = s.replace(/_/g, "/");
|
||||
|
||||
// Replace padding if it was stripped by the sender.
|
||||
// See http://tools.ietf.org/html/rfc4648#section-4
|
||||
switch (s.length % 4) {
|
||||
case 0:
|
||||
break; // No pad chars in this case
|
||||
case 2:
|
||||
s += "==";
|
||||
break; // Two pad chars
|
||||
case 3:
|
||||
s += "=";
|
||||
break; // One pad char
|
||||
default:
|
||||
throw new InputException("Illegal base64url string!");
|
||||
}
|
||||
|
||||
// With correct padding restored, apply the standard base64 decoder
|
||||
return atob(s);
|
||||
}
|
||||
|
||||
// create a mock "doc" object, which the Identity Service
|
||||
// uses as a pointer back into the doc object
|
||||
function mock_doc(aIdentity, aOrigin, aDoFunc) {
|
||||
let mockedDoc = {};
|
||||
mockedDoc.id = uuid();
|
||||
mockedDoc.loggedInUser = aIdentity;
|
||||
mockedDoc.origin = aOrigin;
|
||||
mockedDoc["do"] = aDoFunc;
|
||||
mockedDoc._mm = TEST_MESSAGE_MANAGER;
|
||||
mockedDoc.doReady = partial(aDoFunc, "ready");
|
||||
mockedDoc.doLogin = partial(aDoFunc, "login");
|
||||
mockedDoc.doLogout = partial(aDoFunc, "logout");
|
||||
mockedDoc.doError = partial(aDoFunc, "error");
|
||||
mockedDoc.doCancel = partial(aDoFunc, "cancel");
|
||||
mockedDoc.doCoffee = partial(aDoFunc, "coffee");
|
||||
mockedDoc.childProcessShutdown = partial(aDoFunc, "child-process-shutdown");
|
||||
|
||||
mockedDoc.RP = mockedDoc;
|
||||
|
||||
return mockedDoc;
|
||||
}
|
||||
|
||||
function mock_fxa_rp(aIdentity, aOrigin, aDoFunc) {
|
||||
let mockedDoc = {};
|
||||
mockedDoc.id = uuid();
|
||||
mockedDoc.emailHint = aIdentity;
|
||||
mockedDoc.origin = aOrigin;
|
||||
mockedDoc.wantIssuer = "firefox-accounts";
|
||||
mockedDoc._mm = TEST_MESSAGE_MANAGER;
|
||||
|
||||
mockedDoc.doReady = partial(aDoFunc, "ready");
|
||||
mockedDoc.doLogin = partial(aDoFunc, "login");
|
||||
mockedDoc.doLogout = partial(aDoFunc, "logout");
|
||||
mockedDoc.doError = partial(aDoFunc, "error");
|
||||
mockedDoc.doCancel = partial(aDoFunc, "cancel");
|
||||
mockedDoc.childProcessShutdown = partial(aDoFunc, "child-process-shutdown");
|
||||
|
||||
mockedDoc.RP = mockedDoc;
|
||||
|
||||
return mockedDoc;
|
||||
}
|
||||
|
||||
// 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.
|
||||
function makeObserver(aObserveTopic, aObserveFunc) {
|
||||
let observer = {
|
||||
// nsISupports provides type management in C++
|
||||
// nsIObserver is to be an observer
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports, Ci.nsIObserver]),
|
||||
|
||||
observe: function (aSubject, aTopic, aData) {
|
||||
if (aTopic == aObserveTopic) {
|
||||
aObserveFunc(aSubject, aTopic, aData);
|
||||
Services.obs.removeObserver(observer, aObserveTopic);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, aObserveTopic, false);
|
||||
}
|
||||
|
||||
// set up the ID service with an identity with keypair and all
|
||||
// when ready, invoke callback with the identity
|
||||
function setup_test_identity(identity, cert, cb) {
|
||||
// set up the store so that we're supposed to be logged in
|
||||
let store = get_idstore();
|
||||
|
||||
function keyGenerated(err, kpo) {
|
||||
store.addIdentity(identity, kpo, cert);
|
||||
cb();
|
||||
}
|
||||
|
||||
jwcrypto.generateKeyPair("DS160", keyGenerated);
|
||||
}
|
||||
|
||||
// takes a list of functions and returns a function that
|
||||
// when called the first time, calls the first func,
|
||||
// then the next time the second, etc.
|
||||
function call_sequentially() {
|
||||
let numCalls = 0;
|
||||
let funcs = arguments;
|
||||
|
||||
return function() {
|
||||
if (!funcs[numCalls]) {
|
||||
let argString = Array.prototype.slice.call(arguments).join(",");
|
||||
do_throw("Too many calls: " + argString);
|
||||
return;
|
||||
}
|
||||
funcs[numCalls].apply(funcs[numCalls], arguments);
|
||||
numCalls += 1;
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* Setup a provisioning workflow with appropriate callbacks
|
||||
*
|
||||
* identity is the email we're provisioning.
|
||||
*
|
||||
* afterSetupCallback is required.
|
||||
*
|
||||
* doneProvisioningCallback is optional, if the caller
|
||||
* wants to be notified when the whole provisioning workflow is done
|
||||
*
|
||||
* frameCallbacks is optional, contains the callbacks that the sandbox
|
||||
* frame would provide in response to DOM calls.
|
||||
*/
|
||||
function setup_provisioning(identity, afterSetupCallback, doneProvisioningCallback, callerCallbacks) {
|
||||
IDService.reset();
|
||||
|
||||
let provId = uuid();
|
||||
IDService.IDP._provisionFlows[provId] = {
|
||||
identity : identity,
|
||||
idpParams: TEST_IDPPARAMS,
|
||||
callback: function(err) {
|
||||
if (doneProvisioningCallback)
|
||||
doneProvisioningCallback(err);
|
||||
},
|
||||
sandbox: {
|
||||
// Emulate the free() method on the iframe sandbox
|
||||
free: function() {}
|
||||
}
|
||||
};
|
||||
|
||||
let caller = {};
|
||||
caller.id = provId;
|
||||
caller.doBeginProvisioningCallback = function(id, duration_s) {
|
||||
if (callerCallbacks && callerCallbacks.beginProvisioningCallback)
|
||||
callerCallbacks.beginProvisioningCallback(id, duration_s);
|
||||
};
|
||||
caller.doGenKeyPairCallback = function(pk) {
|
||||
if (callerCallbacks && callerCallbacks.genKeyPairCallback)
|
||||
callerCallbacks.genKeyPairCallback(pk);
|
||||
};
|
||||
|
||||
afterSetupCallback(caller);
|
||||
}
|
||||
|
||||
// Switch debug messages on by default
|
||||
var initialPrefDebugValue = false;
|
||||
try {
|
||||
initialPrefDebugValue = Services.prefs.getBoolPref("toolkit.identity.debug");
|
||||
} catch (noPref) {}
|
||||
Services.prefs.setBoolPref("toolkit.identity.debug", true);
|
||||
|
||||
// Switch on firefox accounts
|
||||
var initialPrefFXAValue = false;
|
||||
try {
|
||||
initialPrefFXAValue = Services.prefs.getBoolPref("identity.fxaccounts.enabled");
|
||||
} catch (noPref) {}
|
||||
Services.prefs.setBoolPref("identity.fxaccounts.enabled", true);
|
||||
|
||||
// after execution, restore prefs
|
||||
do_register_cleanup(function() {
|
||||
log("restoring prefs to their initial values");
|
||||
Services.prefs.setBoolPref("toolkit.identity.debug", initialPrefDebugValue);
|
||||
Services.prefs.setBoolPref("identity.fxaccounts.enabled", initialPrefFXAValue);
|
||||
});
|
||||
|
||||
|
||||
8
toolkit/identity/tests/unit/tail_identity.js
Normal file
8
toolkit/identity/tests/unit/tail_identity.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
// pre-emptively shut down to clear resources
|
||||
if (typeof IdentityService !== "undefined") {
|
||||
IdentityService.shutdown();
|
||||
} else if (typeof IDService !== "undefined") {
|
||||
IDService.shutdown();
|
||||
}
|
||||
|
||||
159
toolkit/identity/tests/unit/test_authentication.js
Normal file
159
toolkit/identity/tests/unit/test_authentication.js
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "IDService",
|
||||
"resource://gre/modules/identity/Identity.jsm",
|
||||
"IdentityService");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto",
|
||||
"resource://gre/modules/identity/jwcrypto.jsm");
|
||||
|
||||
function test_begin_authentication_flow() {
|
||||
do_test_pending();
|
||||
let _provId = null;
|
||||
|
||||
// set up a watch, to be consistent
|
||||
let mockedDoc = mock_doc(null, TEST_URL, function(action, params) {});
|
||||
IDService.RP.watch(mockedDoc);
|
||||
|
||||
// The identity-auth notification is sent up to the UX from the
|
||||
// _doAuthentication function. Be ready to receive it and call
|
||||
// beginAuthentication
|
||||
makeObserver("identity-auth", function (aSubject, aTopic, aData) {
|
||||
do_check_neq(aSubject, null);
|
||||
|
||||
do_check_eq(aSubject.wrappedJSObject.provId, _provId);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
setup_provisioning(
|
||||
TEST_USER,
|
||||
function(caller) {
|
||||
_provId = caller.id;
|
||||
IDService.IDP.beginProvisioning(caller);
|
||||
}, function() {},
|
||||
{
|
||||
beginProvisioningCallback: function(email, duration_s) {
|
||||
|
||||
// let's say this user needs to authenticate
|
||||
IDService.IDP._doAuthentication(_provId, {idpParams:TEST_IDPPARAMS});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function test_complete_authentication_flow() {
|
||||
do_test_pending();
|
||||
let _provId = null;
|
||||
let _authId = null;
|
||||
let id = TEST_USER;
|
||||
|
||||
let callbacksFired = false;
|
||||
let loginStateChanged = false;
|
||||
let identityAuthComplete = false;
|
||||
|
||||
// The result of authentication should be a successful login
|
||||
IDService.reset();
|
||||
|
||||
setup_test_identity(id, TEST_CERT, function() {
|
||||
// set it up so we're supposed to be logged in to TEST_URL
|
||||
|
||||
get_idstore().setLoginState(TEST_URL, true, id);
|
||||
|
||||
// When we authenticate, our ready callback will be fired.
|
||||
// At the same time, a separate topic will be sent up to the
|
||||
// the observer in the UI. The test is complete when both
|
||||
// events have occurred.
|
||||
let mockedDoc = mock_doc(id, TEST_URL, call_sequentially(
|
||||
function(action, params) {
|
||||
do_check_eq(action, 'ready');
|
||||
do_check_eq(params, undefined);
|
||||
|
||||
// if notification already received by observer, test is done
|
||||
callbacksFired = true;
|
||||
if (loginStateChanged && identityAuthComplete) {
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
}
|
||||
));
|
||||
|
||||
makeObserver("identity-auth-complete", function(aSubject, aTopic, aData) {
|
||||
identityAuthComplete = true;
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
makeObserver("identity-login-state-changed", function (aSubject, aTopic, aData) {
|
||||
do_check_neq(aSubject, null);
|
||||
|
||||
do_check_eq(aSubject.wrappedJSObject.rpId, mockedDoc.id);
|
||||
do_check_eq(aData, id);
|
||||
|
||||
// if callbacks in caller doc already fired, test is done.
|
||||
loginStateChanged = true;
|
||||
if (callbacksFired && identityAuthComplete) {
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
});
|
||||
|
||||
IDService.RP.watch(mockedDoc);
|
||||
|
||||
// Create a provisioning flow for our auth flow to attach to
|
||||
setup_provisioning(
|
||||
TEST_USER,
|
||||
function(provFlow) {
|
||||
_provId = provFlow.id;
|
||||
|
||||
IDService.IDP.beginProvisioning(provFlow);
|
||||
}, function() {},
|
||||
{
|
||||
beginProvisioningCallback: function(email, duration_s) {
|
||||
// let's say this user needs to authenticate
|
||||
IDService.IDP._doAuthentication(_provId, {idpParams:TEST_IDPPARAMS});
|
||||
|
||||
// test_begin_authentication_flow verifies that the right
|
||||
// message is sent to the UI. So that works. Moving on,
|
||||
// the UI calls setAuthenticationFlow ...
|
||||
_authId = uuid();
|
||||
IDService.IDP.setAuthenticationFlow(_authId, _provId);
|
||||
|
||||
// ... then the UI calls beginAuthentication ...
|
||||
authCaller.id = _authId;
|
||||
IDService.IDP._provisionFlows[_provId].caller = authCaller;
|
||||
IDService.IDP.beginAuthentication(authCaller);
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// A mock calling context
|
||||
let authCaller = {
|
||||
doBeginAuthenticationCallback: function doBeginAuthenticationCallback(identity) {
|
||||
do_check_eq(identity, TEST_USER);
|
||||
// completeAuthentication will emit "identity-auth-complete"
|
||||
IDService.IDP.completeAuthentication(_authId);
|
||||
},
|
||||
|
||||
doError: function(err) {
|
||||
log("OW! My doError callback hurts!", err);
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
var TESTS = [];
|
||||
|
||||
TESTS.push(test_begin_authentication_flow);
|
||||
TESTS.push(test_complete_authentication_flow);
|
||||
|
||||
TESTS.forEach(add_test);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
122
toolkit/identity/tests/unit/test_crypto_service.js
Normal file
122
toolkit/identity/tests/unit/test_crypto_service.js
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/* 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");
|
||||
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";
|
||||
|
||||
const BASE64_URL_ENCODINGS = [
|
||||
// The vectors from RFC 4648 are very silly, but we may as well include them.
|
||||
["", ""],
|
||||
["f", "Zg=="],
|
||||
["fo", "Zm8="],
|
||||
["foo", "Zm9v"],
|
||||
["foob", "Zm9vYg=="],
|
||||
["fooba", "Zm9vYmE="],
|
||||
["foobar", "Zm9vYmFy"],
|
||||
|
||||
// It's quite likely you could get a string like this in an assertion audience
|
||||
["i-like-pie.com", "aS1saWtlLXBpZS5jb20="],
|
||||
|
||||
// A few extra to be really sure
|
||||
["andré@example.com", "YW5kcsOpQGV4YW1wbGUuY29t"],
|
||||
["πόλλ' οἶδ' ἀλώπηξ, ἀλλ' ἐχῖνος ἓν μέγα",
|
||||
"z4DPjM67zrsnIM6_4by2zrQnIOG8gM67z47PgM63zr4sIOG8gM67zrsnIOG8kM-H4b-Wzr3Ov8-CIOG8k869IM68zq3Os86x"],
|
||||
];
|
||||
|
||||
// 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_base64_roundtrip() {
|
||||
let message = "Attack at dawn!";
|
||||
let encoded = idService.base64UrlEncode(message);
|
||||
let decoded = base64UrlDecode(encoded);
|
||||
do_check_neq(message, encoded);
|
||||
do_check_eq(decoded, message);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_dsa() {
|
||||
idService.generateKeyPair(ALG_DSA, function (rv, keyPair) {
|
||||
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
|
||||
|
||||
log("about to sign with DSA key");
|
||||
keyPair.sign("foo", function (rv2, signature) {
|
||||
log("DSA sign finished ", rv2, signature);
|
||||
do_check_true(Components.isSuccessCode(rv2));
|
||||
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) {
|
||||
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);
|
||||
|
||||
log("about to sign with RSA key");
|
||||
keyPair.sign("foo", function (rv2, signature) {
|
||||
log("RSA sign finished ", rv2, signature);
|
||||
do_check_true(Components.isSuccessCode(rv2));
|
||||
do_check_true(signature.length > 1);
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function test_base64UrlEncode() {
|
||||
for (let [source, target] of BASE64_URL_ENCODINGS) {
|
||||
do_check_eq(target, idService.base64UrlEncode(source));
|
||||
}
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_base64UrlDecode() {
|
||||
let utf8Converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
|
||||
.createInstance(Ci.nsIScriptableUnicodeConverter);
|
||||
utf8Converter.charset = "UTF-8";
|
||||
|
||||
// We know the encoding of our inputs - on conversion back out again, make
|
||||
// sure they're the same.
|
||||
for (let [source, target] of BASE64_URL_ENCODINGS) {
|
||||
let result = utf8Converter.ConvertToUnicode(base64UrlDecode(target));
|
||||
result += utf8Converter.Finish();
|
||||
do_check_eq(source, result);
|
||||
}
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_test(test_base64_roundtrip);
|
||||
add_test(test_dsa);
|
||||
add_test(test_rsa);
|
||||
add_test(test_base64UrlEncode);
|
||||
add_test(test_base64UrlDecode);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
270
toolkit/identity/tests/unit/test_firefox_accounts.js
Normal file
270
toolkit/identity/tests/unit/test_firefox_accounts.js
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/DOMIdentity.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FirefoxAccounts",
|
||||
"resource://gre/modules/identity/FirefoxAccounts.jsm");
|
||||
|
||||
// Make the profile dir available; this is necessary so that
|
||||
// services/fxaccounts/FxAccounts.jsm can read and write its signed-in user
|
||||
// data.
|
||||
do_get_profile();
|
||||
|
||||
function MockFXAManager() {
|
||||
this.signedInUser = true;
|
||||
}
|
||||
MockFXAManager.prototype = {
|
||||
getAssertion: function(audience) {
|
||||
let result = this.signedInUser ? TEST_ASSERTION : null;
|
||||
return Promise.resolve(result);
|
||||
},
|
||||
|
||||
signOut: function() {
|
||||
this.signedInUser = false;
|
||||
return Promise.resolve(null);
|
||||
},
|
||||
|
||||
signIn: function(user) {
|
||||
this.signedInUser = user;
|
||||
return Promise.resolve(user);
|
||||
},
|
||||
}
|
||||
|
||||
var originalManager = FirefoxAccounts.fxAccountsManager;
|
||||
FirefoxAccounts.fxAccountsManager = new MockFXAManager();
|
||||
do_register_cleanup(() => {
|
||||
log("restoring fxaccountsmanager");
|
||||
FirefoxAccounts.fxAccountsManager = originalManager;
|
||||
});
|
||||
|
||||
function withNobodySignedIn() {
|
||||
return FirefoxAccounts.fxAccountsManager.signOut();
|
||||
}
|
||||
|
||||
function withSomebodySignedIn() {
|
||||
return FirefoxAccounts.fxAccountsManager.signIn('Pertelote');
|
||||
}
|
||||
|
||||
function test_overall() {
|
||||
do_check_neq(FirefoxAccounts, null);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_mock() {
|
||||
do_test_pending();
|
||||
|
||||
withSomebodySignedIn().then(() => {
|
||||
FirefoxAccounts.fxAccountsManager.getAssertion().then(assertion => {
|
||||
do_check_eq(assertion, TEST_ASSERTION);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function test_watch_signed_in() {
|
||||
do_test_pending();
|
||||
|
||||
let received = [];
|
||||
|
||||
let mockedRP = mock_fxa_rp(null, TEST_URL, function(method, data) {
|
||||
received.push([method, data]);
|
||||
|
||||
if (method == "ready") {
|
||||
// confirm that we were signed in and then ready was called
|
||||
do_check_eq(received.length, 2);
|
||||
do_check_eq(received[0][0], "login");
|
||||
do_check_eq(received[0][1], TEST_ASSERTION);
|
||||
do_check_eq(received[1][0], "ready");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
});
|
||||
|
||||
withSomebodySignedIn().then(() => {
|
||||
FirefoxAccounts.RP.watch(mockedRP);
|
||||
});
|
||||
}
|
||||
|
||||
function test_watch_signed_out() {
|
||||
do_test_pending();
|
||||
|
||||
let received = [];
|
||||
|
||||
let mockedRP = mock_fxa_rp(null, TEST_URL, function(method) {
|
||||
received.push(method);
|
||||
|
||||
if (method == "ready") {
|
||||
// confirm that we were signed out and then ready was called
|
||||
do_check_eq(received.length, 2);
|
||||
do_check_eq(received[0], "logout");
|
||||
do_check_eq(received[1], "ready");
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
});
|
||||
|
||||
withNobodySignedIn().then(() => {
|
||||
FirefoxAccounts.RP.watch(mockedRP);
|
||||
});
|
||||
}
|
||||
|
||||
function test_request() {
|
||||
do_test_pending();
|
||||
|
||||
let received = [];
|
||||
|
||||
let mockedRP = mock_fxa_rp(null, TEST_URL, function(method, data) {
|
||||
received.push([method, data]);
|
||||
|
||||
// On watch(), we are signed out. Then we call request().
|
||||
if (received.length === 2) {
|
||||
do_check_eq(received[0][0], "logout");
|
||||
do_check_eq(received[1][0], "ready");
|
||||
|
||||
// Pretend request() showed ux and the user signed in
|
||||
withSomebodySignedIn().then(() => {
|
||||
FirefoxAccounts.RP.request(mockedRP.id);
|
||||
});
|
||||
}
|
||||
|
||||
if (received.length === 3) {
|
||||
do_check_eq(received[2][0], "login");
|
||||
do_check_eq(received[2][1], TEST_ASSERTION);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
});
|
||||
|
||||
// First, call watch() with nobody signed in
|
||||
withNobodySignedIn().then(() => {
|
||||
FirefoxAccounts.RP.watch(mockedRP);
|
||||
});
|
||||
}
|
||||
|
||||
function test_logout() {
|
||||
do_test_pending();
|
||||
|
||||
let received = [];
|
||||
|
||||
let mockedRP = mock_fxa_rp(null, TEST_URL, function(method) {
|
||||
received.push(method);
|
||||
|
||||
// At first, watch() signs us in automatically. Then we sign out.
|
||||
if (received.length === 2) {
|
||||
do_check_eq(received[0], "login");
|
||||
do_check_eq(received[1], "ready");
|
||||
|
||||
FirefoxAccounts.RP.logout(mockedRP.id);
|
||||
}
|
||||
|
||||
if (received.length === 3) {
|
||||
do_check_eq(received[2], "logout");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
});
|
||||
|
||||
// First, call watch()
|
||||
withSomebodySignedIn().then(() => {
|
||||
FirefoxAccounts.RP.watch(mockedRP);
|
||||
});
|
||||
}
|
||||
|
||||
function test_error() {
|
||||
do_test_pending();
|
||||
|
||||
let received = [];
|
||||
|
||||
// Mock the fxAccountsManager so that getAssertion rejects its promise and
|
||||
// triggers our onerror handler. (This is the method that's used internally
|
||||
// by FirefoxAccounts.RP.request().)
|
||||
let originalGetAssertion = FirefoxAccounts.fxAccountsManager.getAssertion;
|
||||
FirefoxAccounts.fxAccountsManager.getAssertion = function(audience) {
|
||||
return Promise.reject(new Error("barf!"));
|
||||
};
|
||||
|
||||
let mockedRP = mock_fxa_rp(null, TEST_URL, function(method, message) {
|
||||
// We will immediately receive an error, due to watch()'s attempt
|
||||
// to getAssertion().
|
||||
do_check_eq(method, "error");
|
||||
do_check_true(/barf/.test(message));
|
||||
|
||||
// Put things back the way they were
|
||||
FirefoxAccounts.fxAccountsManager.getAssertion = originalGetAssertion;
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// First, call watch()
|
||||
withSomebodySignedIn().then(() => {
|
||||
FirefoxAccounts.RP.watch(mockedRP);
|
||||
});
|
||||
}
|
||||
|
||||
function test_child_process_shutdown() {
|
||||
do_test_pending();
|
||||
let rpCount = FirefoxAccounts.RP._rpFlows.size;
|
||||
|
||||
makeObserver("identity-child-process-shutdown", (aTopic, aSubject, aData) => {
|
||||
// Last of all, the shutdown observer message will be fired.
|
||||
// This takes place after the RP has a chance to delete flows
|
||||
// and clean up.
|
||||
do_check_eq(FirefoxAccounts.RP._rpFlows.size, rpCount);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
let mockedRP = mock_fxa_rp(null, TEST_URL, (method) => {
|
||||
// We should enter this function for 'ready' and 'child-process-shutdown'.
|
||||
// After we have a chance to do our thing, the shutdown observer message
|
||||
// will fire and be caught by the function above.
|
||||
do_check_eq(FirefoxAccounts.RP._rpFlows.size, rpCount + 1);
|
||||
switch (method) {
|
||||
case "ready":
|
||||
DOMIdentity._childProcessShutdown("my message manager");
|
||||
break;
|
||||
|
||||
case "child-process-shutdown":
|
||||
// We have to call this explicitly because there's no real
|
||||
// dom window here.
|
||||
FirefoxAccounts.RP.childProcessShutdown(mockedRP._mm);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
mockedRP._mm = "my message manager";
|
||||
withSomebodySignedIn().then(() => {
|
||||
FirefoxAccounts.RP.watch(mockedRP);
|
||||
});
|
||||
|
||||
// fake a dom window context
|
||||
DOMIdentity.newContext(mockedRP, mockedRP._mm);
|
||||
}
|
||||
|
||||
var TESTS = [
|
||||
test_overall,
|
||||
test_mock,
|
||||
test_watch_signed_in,
|
||||
test_watch_signed_out,
|
||||
test_request,
|
||||
test_logout,
|
||||
test_error,
|
||||
test_child_process_shutdown,
|
||||
];
|
||||
|
||||
TESTS.forEach(add_test);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
114
toolkit/identity/tests/unit/test_identity.js
Normal file
114
toolkit/identity/tests/unit/test_identity.js
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "IDService",
|
||||
"resource://gre/modules/identity/Identity.jsm",
|
||||
"IdentityService");
|
||||
|
||||
function test_overall() {
|
||||
do_check_neq(IDService, null);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_mock_doc() {
|
||||
do_test_pending();
|
||||
let mockedDoc = mock_doc(null, TEST_URL, function(action, params) {
|
||||
do_check_eq(action, 'coffee');
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
mockedDoc.doCoffee();
|
||||
}
|
||||
|
||||
function test_add_identity() {
|
||||
IDService.reset();
|
||||
|
||||
IDService.addIdentity(TEST_USER);
|
||||
|
||||
let identities = IDService.RP.getIdentitiesForSite(TEST_URL);
|
||||
do_check_eq(identities.result.length, 1);
|
||||
do_check_eq(identities.result[0], TEST_USER);
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_select_identity() {
|
||||
do_test_pending();
|
||||
|
||||
IDService.reset();
|
||||
|
||||
let id = "ishtar@mockmyid.com";
|
||||
setup_test_identity(id, TEST_CERT, function() {
|
||||
let gotAssertion = false;
|
||||
let mockedDoc = mock_doc(null, TEST_URL, call_sequentially(
|
||||
function(action, params) {
|
||||
// ready emitted from first watch() call
|
||||
do_check_eq(action, 'ready');
|
||||
do_check_null(params);
|
||||
},
|
||||
// first the login call
|
||||
function(action, params) {
|
||||
do_check_eq(action, 'login');
|
||||
do_check_neq(params, null);
|
||||
|
||||
// XXX - check that the assertion is for the right email
|
||||
|
||||
gotAssertion = true;
|
||||
},
|
||||
// then the ready call
|
||||
function(action, params) {
|
||||
do_check_eq(action, 'ready');
|
||||
do_check_null(params);
|
||||
|
||||
// we should have gotten the assertion already
|
||||
do_check_true(gotAssertion);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}));
|
||||
|
||||
// register the callbacks
|
||||
IDService.RP.watch(mockedDoc);
|
||||
|
||||
// register the request UX observer
|
||||
makeObserver("identity-request", function (aSubject, aTopic, aData) {
|
||||
// do the select identity
|
||||
// we expect this to succeed right away because of test_identity
|
||||
// so we don't mock network requests or otherwise
|
||||
IDService.selectIdentity(aSubject.wrappedJSObject.rpId, id);
|
||||
});
|
||||
|
||||
// do the request
|
||||
IDService.RP.request(mockedDoc.id, {});
|
||||
});
|
||||
}
|
||||
|
||||
function test_parse_good_email() {
|
||||
var parsed = IDService.parseEmail('prime-minister@jed.gov');
|
||||
do_check_eq(parsed.username, 'prime-minister');
|
||||
do_check_eq(parsed.domain, 'jed.gov');
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_parse_bogus_emails() {
|
||||
do_check_eq(null, IDService.parseEmail('@evil.org'));
|
||||
do_check_eq(null, IDService.parseEmail('foo@bar@baz.com'));
|
||||
do_check_eq(null, IDService.parseEmail('you@wellsfargo.com/accounts/transfer?to=dolske&amt=all'));
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
var TESTS = [test_overall, test_mock_doc];
|
||||
|
||||
TESTS.push(test_add_identity);
|
||||
TESTS.push(test_select_identity);
|
||||
TESTS.push(test_parse_good_email);
|
||||
TESTS.push(test_parse_bogus_emails);
|
||||
|
||||
TESTS.forEach(add_test);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
46
toolkit/identity/tests/unit/test_identity_utils.js
Normal file
46
toolkit/identity/tests/unit/test_identity_utils.js
Normal 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();
|
||||
}
|
||||
|
||||
var TESTS = [
|
||||
test_check_deprecated,
|
||||
test_check_renamed
|
||||
];
|
||||
|
||||
TESTS.forEach(add_test);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
281
toolkit/identity/tests/unit/test_jwcrypto.js
Normal file
281
toolkit/identity/tests/unit/test_jwcrypto.js
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
/* 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.defineLazyServiceGetter(this,
|
||||
"CryptoService",
|
||||
"@mozilla.org/identity/crypto-service;1",
|
||||
"nsIIdentityCryptoService");
|
||||
|
||||
const RP_ORIGIN = "http://123done.org";
|
||||
const INTERNAL_ORIGIN = "browserid://";
|
||||
|
||||
const SECOND_MS = 1000;
|
||||
const MINUTE_MS = SECOND_MS * 60;
|
||||
const HOUR_MS = MINUTE_MS * 60;
|
||||
|
||||
function test_sanity() {
|
||||
do_test_pending();
|
||||
|
||||
jwcrypto.generateKeyPair("DS160", function(err, kp) {
|
||||
do_check_null(err);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
}
|
||||
|
||||
function test_generate() {
|
||||
do_test_pending();
|
||||
jwcrypto.generateKeyPair("DS160", function(err, kp) {
|
||||
do_check_null(err);
|
||||
do_check_neq(kp, null);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
}
|
||||
|
||||
function test_get_assertion() {
|
||||
do_test_pending();
|
||||
|
||||
jwcrypto.generateKeyPair(
|
||||
"DS160",
|
||||
function(err, kp) {
|
||||
jwcrypto.generateAssertion("fake-cert", kp, RP_ORIGIN, (err2, backedAssertion) => {
|
||||
do_check_null(err2);
|
||||
|
||||
do_check_eq(backedAssertion.split("~").length, 2);
|
||||
do_check_eq(backedAssertion.split(".").length, 3);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function test_rsa() {
|
||||
do_test_pending();
|
||||
function checkRSA(err, kpo) {
|
||||
do_check_neq(kpo, undefined);
|
||||
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);
|
||||
do_check_neq(kpo.exponent, null);
|
||||
do_check_neq(kpo.modulus, null);
|
||||
|
||||
// TODO: should sign be async?
|
||||
let sig = kpo.sign("This is a message to sign");
|
||||
|
||||
do_check_neq(sig, null);
|
||||
do_check_eq(typeof sig, "string");
|
||||
do_check_true(sig.length > 1);
|
||||
*/
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
jwcrypto.generateKeyPair("RS256", checkRSA);
|
||||
}
|
||||
|
||||
function test_dsa() {
|
||||
do_test_pending();
|
||||
function checkDSA(err, kpo) {
|
||||
do_check_neq(kpo, undefined);
|
||||
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);
|
||||
do_check_neq(kpo.generator, null);
|
||||
do_check_neq(kpo.prime, null);
|
||||
do_check_neq(kpo.subPrime, null);
|
||||
do_check_neq(kpo.publicValue, null);
|
||||
|
||||
let sig = kpo.sign("This is a message to sign");
|
||||
|
||||
do_check_neq(sig, null);
|
||||
do_check_eq(typeof sig, "string");
|
||||
do_check_true(sig.length > 1);
|
||||
*/
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
jwcrypto.generateKeyPair("DS160", checkDSA);
|
||||
}
|
||||
|
||||
function test_get_assertion_with_offset() {
|
||||
do_test_pending();
|
||||
|
||||
|
||||
// Use an arbitrary date in the past to ensure we don't accidentally pass
|
||||
// this test with current dates, missing offsets, etc.
|
||||
let serverMsec = Date.parse("Tue Oct 31 2000 00:00:00 GMT-0800");
|
||||
|
||||
// local clock skew
|
||||
// clock is 12 hours fast; -12 hours offset must be applied
|
||||
let localtimeOffsetMsec = -1 * 12 * HOUR_MS;
|
||||
let localMsec = serverMsec - localtimeOffsetMsec;
|
||||
|
||||
jwcrypto.generateKeyPair(
|
||||
"DS160",
|
||||
function(err, kp) {
|
||||
jwcrypto.generateAssertion("fake-cert", kp, RP_ORIGIN,
|
||||
{ duration: MINUTE_MS,
|
||||
localtimeOffsetMsec: localtimeOffsetMsec,
|
||||
now: localMsec},
|
||||
function(err2, backedAssertion) {
|
||||
do_check_null(err2);
|
||||
|
||||
// properly formed
|
||||
let cert;
|
||||
let assertion;
|
||||
[cert, assertion] = backedAssertion.split("~");
|
||||
|
||||
do_check_eq(cert, "fake-cert");
|
||||
do_check_eq(assertion.split(".").length, 3);
|
||||
|
||||
let components = extractComponents(assertion);
|
||||
|
||||
// Expiry is within two minutes, corrected for skew
|
||||
let exp = parseInt(components.payload.exp, 10);
|
||||
do_check_true(exp - serverMsec === MINUTE_MS);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function test_assertion_lifetime() {
|
||||
do_test_pending();
|
||||
|
||||
jwcrypto.generateKeyPair(
|
||||
"DS160",
|
||||
function(err, kp) {
|
||||
jwcrypto.generateAssertion("fake-cert", kp, RP_ORIGIN,
|
||||
{duration: MINUTE_MS},
|
||||
function(err2, backedAssertion) {
|
||||
do_check_null(err2);
|
||||
|
||||
// properly formed
|
||||
let cert;
|
||||
let assertion;
|
||||
[cert, assertion] = backedAssertion.split("~");
|
||||
|
||||
do_check_eq(cert, "fake-cert");
|
||||
do_check_eq(assertion.split(".").length, 3);
|
||||
|
||||
let components = extractComponents(assertion);
|
||||
|
||||
// Expiry is within one minute, as we specified above
|
||||
let exp = parseInt(components.payload.exp, 10);
|
||||
do_check_true(Math.abs(Date.now() - exp) > 50 * SECOND_MS);
|
||||
do_check_true(Math.abs(Date.now() - exp) <= MINUTE_MS);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function test_audience_encoding_bug972582() {
|
||||
let audience = "i-like-pie.com";
|
||||
|
||||
jwcrypto.generateKeyPair(
|
||||
"DS160",
|
||||
function(err, kp) {
|
||||
do_check_null(err);
|
||||
jwcrypto.generateAssertion("fake-cert", kp, audience,
|
||||
function(err2, backedAssertion) {
|
||||
do_check_null(err2);
|
||||
|
||||
let [cert, assertion] = backedAssertion.split("~");
|
||||
let components = extractComponents(assertion);
|
||||
do_check_eq(components.payload.aud, audience);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// End of tests
|
||||
// Helper function follow
|
||||
|
||||
function extractComponents(signedObject) {
|
||||
if (typeof(signedObject) != 'string') {
|
||||
throw new Error("malformed signature " + typeof(signedObject));
|
||||
}
|
||||
|
||||
let parts = signedObject.split(".");
|
||||
if (parts.length != 3) {
|
||||
throw new Error("signed object must have three parts, this one has " + parts.length);
|
||||
}
|
||||
|
||||
let headerSegment = parts[0];
|
||||
let payloadSegment = parts[1];
|
||||
let cryptoSegment = parts[2];
|
||||
|
||||
let header = JSON.parse(base64UrlDecode(headerSegment));
|
||||
let payload = JSON.parse(base64UrlDecode(payloadSegment));
|
||||
|
||||
// Ensure well-formed header
|
||||
do_check_eq(Object.keys(header).length, 1);
|
||||
do_check_true(!!header.alg);
|
||||
|
||||
// Ensure well-formed payload
|
||||
for (let field of ["exp", "aud"]) {
|
||||
do_check_true(!!payload[field]);
|
||||
}
|
||||
|
||||
return {header: header,
|
||||
payload: payload,
|
||||
headerSegment: headerSegment,
|
||||
payloadSegment: payloadSegment,
|
||||
cryptoSegment: cryptoSegment};
|
||||
}
|
||||
|
||||
var TESTS = [
|
||||
test_sanity,
|
||||
test_generate,
|
||||
test_get_assertion,
|
||||
test_get_assertion_with_offset,
|
||||
test_assertion_lifetime,
|
||||
test_audience_encoding_bug972582,
|
||||
];
|
||||
|
||||
TESTS = TESTS.concat([test_rsa, test_dsa]);
|
||||
|
||||
TESTS.forEach(add_test);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
20
toolkit/identity/tests/unit/test_load_modules.js
Normal file
20
toolkit/identity/tests/unit/test_load_modules.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/* 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/. */
|
||||
|
||||
const modules = [
|
||||
"Identity.jsm",
|
||||
"IdentityProvider.jsm",
|
||||
"IdentityStore.jsm",
|
||||
"jwcrypto.jsm",
|
||||
"RelyingParty.jsm",
|
||||
"Sandbox.jsm",
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
for (let m of modules) {
|
||||
let resource = "resource://gre/modules/identity/" + m;
|
||||
Components.utils.import(resource, {});
|
||||
do_print("loaded " + resource);
|
||||
}
|
||||
}
|
||||
74
toolkit/identity/tests/unit/test_log_utils.js
Normal file
74
toolkit/identity/tests/unit/test_log_utils.js
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
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._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");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_reportError() {
|
||||
Logger.reportError("log test", "We are out of pies!!!");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_wrappers() {
|
||||
logAlias("I like potatoes");
|
||||
do_test_finished();
|
||||
reportErrorAlias("Too much red bull");
|
||||
}
|
||||
|
||||
var TESTS = [
|
||||
// XXX fix me
|
||||
// toggle_debug,
|
||||
test_log,
|
||||
test_reportError,
|
||||
test_wrappers,
|
||||
];
|
||||
|
||||
TESTS.forEach(add_test);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
223
toolkit/identity/tests/unit/test_minimalidentity.js
Normal file
223
toolkit/identity/tests/unit/test_minimalidentity.js
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "MinimalIDService",
|
||||
"resource://gre/modules/identity/MinimalIdentity.jsm",
|
||||
"IdentityService");
|
||||
|
||||
Cu.import("resource://gre/modules/identity/LogUtils.jsm");
|
||||
Cu.import("resource://gre/modules/DOMIdentity.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) {
|
||||
do_check_eq(action, 'coffee');
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
mockedDoc.doCoffee();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that the "identity-controller-watch" signal is emitted correctly
|
||||
*/
|
||||
function test_watch() {
|
||||
do_test_pending();
|
||||
|
||||
let mockedDoc = mock_doc(null, TEST_URL);
|
||||
makeObserver("identity-controller-watch", function (aSubject, aTopic, aData) {
|
||||
do_check_eq(aSubject.wrappedJSObject.id, mockedDoc.id);
|
||||
do_check_eq(aSubject.wrappedJSObject.origin, TEST_URL);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
MinimalIDService.RP.watch(mockedDoc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that the "identity-controller-request" signal is emitted correctly
|
||||
*/
|
||||
function test_request() {
|
||||
do_test_pending();
|
||||
|
||||
let mockedDoc = mock_doc(null, TEST_URL);
|
||||
makeObserver("identity-controller-request", function (aSubject, aTopic, aData) {
|
||||
do_check_eq(aSubject.wrappedJSObject.id, mockedDoc.id);
|
||||
do_check_eq(aSubject.wrappedJSObject.origin, TEST_URL);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
MinimalIDService.RP.watch(mockedDoc);
|
||||
MinimalIDService.RP.request(mockedDoc.id, {});
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that the forceAuthentication flag can be sent
|
||||
*/
|
||||
function test_request_forceAuthentication() {
|
||||
do_test_pending();
|
||||
|
||||
let mockedDoc = mock_doc(null, TEST_URL);
|
||||
makeObserver("identity-controller-request", function (aSubject, aTopic, aData) {
|
||||
do_check_eq(aSubject.wrappedJSObject.id, mockedDoc.id);
|
||||
do_check_eq(aSubject.wrappedJSObject.origin, TEST_URL);
|
||||
do_check_eq(aSubject.wrappedJSObject.forceAuthentication, true);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
MinimalIDService.RP.watch(mockedDoc);
|
||||
MinimalIDService.RP.request(mockedDoc.id, {forceAuthentication: true});
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that the issuer can be forced
|
||||
*/
|
||||
function test_request_forceIssuer() {
|
||||
do_test_pending();
|
||||
|
||||
let mockedDoc = mock_doc(null, TEST_URL);
|
||||
makeObserver("identity-controller-request", function (aSubject, aTopic, aData) {
|
||||
do_check_eq(aSubject.wrappedJSObject.id, mockedDoc.id);
|
||||
do_check_eq(aSubject.wrappedJSObject.origin, TEST_URL);
|
||||
do_check_eq(aSubject.wrappedJSObject.issuer, "https://jed.gov");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
MinimalIDService.RP.watch(mockedDoc);
|
||||
MinimalIDService.RP.request(mockedDoc.id, {issuer: "https://jed.gov"});
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that the "identity-controller-logout" signal is emitted correctly
|
||||
*/
|
||||
function test_logout() {
|
||||
do_test_pending();
|
||||
|
||||
let mockedDoc = mock_doc(null, TEST_URL);
|
||||
makeObserver("identity-controller-logout", function (aSubject, aTopic, aData) {
|
||||
do_check_eq(aSubject.wrappedJSObject.id, mockedDoc.id);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
MinimalIDService.RP.watch(mockedDoc);
|
||||
MinimalIDService.RP.logout(mockedDoc.id, {});
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that logout() before watch() fails gently
|
||||
*/
|
||||
|
||||
function test_logoutBeforeWatch() {
|
||||
do_test_pending();
|
||||
|
||||
let mockedDoc = mock_doc(null, TEST_URL);
|
||||
makeObserver("identity-controller-logout", function() {
|
||||
do_throw("How can we logout when watch was not called?");
|
||||
});
|
||||
|
||||
MinimalIDService.RP.logout(mockedDoc.id, {});
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that request() before watch() fails gently
|
||||
*/
|
||||
|
||||
function test_requestBeforeWatch() {
|
||||
do_test_pending();
|
||||
|
||||
let mockedDoc = mock_doc(null, TEST_URL);
|
||||
makeObserver("identity-controller-request", function() {
|
||||
do_throw("How can we request when watch was not called?");
|
||||
});
|
||||
|
||||
MinimalIDService.RP.request(mockedDoc.id, {});
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that internal unwatch() before watch() fails gently
|
||||
*/
|
||||
|
||||
function test_unwatchBeforeWatch() {
|
||||
do_test_pending();
|
||||
|
||||
let mockedDoc = mock_doc(null, TEST_URL);
|
||||
|
||||
MinimalIDService.RP.unwatch(mockedDoc.id, {});
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
/*
|
||||
* Test that the RP flow is cleaned up on child process shutdown
|
||||
*/
|
||||
|
||||
function test_childProcessShutdown() {
|
||||
do_test_pending();
|
||||
let UNIQUE_MESSAGE_MANAGER = "i am a beautiful snowflake";
|
||||
let initialRPCount = Object.keys(MinimalIDService.RP._rpFlows).length;
|
||||
|
||||
let mockedDoc = mock_doc(null, TEST_URL, (action, params) => {
|
||||
if (action == "child-process-shutdown") {
|
||||
// since there's no actual dom window connection, we have to
|
||||
// do this bit manually here.
|
||||
MinimalIDService.RP.childProcessShutdown(UNIQUE_MESSAGE_MANAGER);
|
||||
}
|
||||
});
|
||||
mockedDoc._mm = UNIQUE_MESSAGE_MANAGER;
|
||||
|
||||
makeObserver("identity-controller-watch", function (aSubject, aTopic, aData) {
|
||||
DOMIdentity._childProcessShutdown(UNIQUE_MESSAGE_MANAGER);
|
||||
});
|
||||
|
||||
makeObserver("identity-child-process-shutdown", (aTopic, aSubject, aData) => {
|
||||
do_check_eq(Object.keys(MinimalIDService.RP._rpFlows).length, initialRPCount);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// fake a dom window context
|
||||
DOMIdentity.newContext(mockedDoc, UNIQUE_MESSAGE_MANAGER);
|
||||
|
||||
MinimalIDService.RP.watch(mockedDoc);
|
||||
}
|
||||
|
||||
var TESTS = [
|
||||
test_overall,
|
||||
test_mock_doc,
|
||||
test_watch,
|
||||
test_request,
|
||||
test_request_forceAuthentication,
|
||||
test_request_forceIssuer,
|
||||
test_logout,
|
||||
test_logoutBeforeWatch,
|
||||
test_requestBeforeWatch,
|
||||
test_unwatchBeforeWatch,
|
||||
test_childProcessShutdown,
|
||||
];
|
||||
|
||||
TESTS.forEach(add_test);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
114
toolkit/identity/tests/unit/test_observer_topics.js
Normal file
114
toolkit/identity/tests/unit/test_observer_topics.js
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* By their nature, these tests duplicate some of the functionality of
|
||||
* other tests for Identity, RelyingParty, and IdentityProvider.
|
||||
*
|
||||
* In particular, "identity-auth-complete" and
|
||||
* "identity-login-state-changed" are tested in test_authentication.js
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "IDService",
|
||||
"resource://gre/modules/identity/Identity.jsm",
|
||||
"IdentityService");
|
||||
|
||||
function test_smoke() {
|
||||
do_check_neq(IDService, null);
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
function test_identity_request() {
|
||||
// In response to navigator.id.request(), initiate a login with user
|
||||
// interaction by notifying observers of 'identity-request'
|
||||
|
||||
do_test_pending();
|
||||
|
||||
IDService.reset();
|
||||
|
||||
let id = "landru@mockmyid.com";
|
||||
setup_test_identity(id, TEST_CERT, function() {
|
||||
// deliberately adding a trailing final slash on the domain
|
||||
// to test path composition
|
||||
let mockedDoc = mock_doc(null, "http://jed.gov/", function() {});
|
||||
|
||||
// by calling watch() we create an rp flow.
|
||||
IDService.RP.watch(mockedDoc);
|
||||
|
||||
// register the request UX observer
|
||||
makeObserver("identity-request", function (aSubject, aTopic, aData) {
|
||||
do_check_eq(aTopic, "identity-request");
|
||||
do_check_eq(aData, null);
|
||||
|
||||
// check that all the URLs are properly resolved
|
||||
let subj = aSubject.wrappedJSObject;
|
||||
do_check_eq(subj.privacyPolicy, "http://jed.gov/pp.html");
|
||||
do_check_eq(subj.termsOfService, "http://jed.gov/tos.html");
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
let requestOptions = {
|
||||
privacyPolicy: "/pp.html",
|
||||
termsOfService: "/tos.html"
|
||||
};
|
||||
IDService.RP.request(mockedDoc.id, requestOptions);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function test_identity_auth() {
|
||||
// see test_authentication.js for "identity-auth-complete"
|
||||
// and "identity-login-state-changed"
|
||||
|
||||
do_test_pending();
|
||||
let _provId = "bogus";
|
||||
|
||||
// Simulate what would be returned by IDService._fetchWellKnownFile
|
||||
// for a given domain.
|
||||
let idpParams = {
|
||||
domain: "myfavoriteflan.com",
|
||||
idpParams: {
|
||||
authentication: "/foo/authenticate.html",
|
||||
provisioning: "/foo/provision.html"
|
||||
}
|
||||
};
|
||||
|
||||
// Create an RP flow
|
||||
let mockedDoc = mock_doc(null, TEST_URL, function(action, params) {});
|
||||
IDService.RP.watch(mockedDoc);
|
||||
|
||||
// The identity-auth notification is sent up to the UX from the
|
||||
// _doAuthentication function. Be ready to receive it and call
|
||||
// beginAuthentication
|
||||
makeObserver("identity-auth", function (aSubject, aTopic, aData) {
|
||||
do_check_neq(aSubject, null);
|
||||
do_check_eq(aTopic, "identity-auth");
|
||||
do_check_eq(aData, "https://myfavoriteflan.com/foo/authenticate.html");
|
||||
|
||||
do_check_eq(aSubject.wrappedJSObject.provId, _provId);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
// Even though our provisioning flow id is bogus, IdentityProvider
|
||||
// won't look at it until farther along in the authentication
|
||||
// process. So this test can pass with a fake provId.
|
||||
IDService.IDP._doAuthentication(_provId, idpParams);
|
||||
}
|
||||
|
||||
var TESTS = [
|
||||
test_smoke,
|
||||
test_identity_request,
|
||||
test_identity_auth,
|
||||
];
|
||||
|
||||
|
||||
TESTS.forEach(add_test);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
242
toolkit/identity/tests/unit/test_provisioning.js
Normal file
242
toolkit/identity/tests/unit/test_provisioning.js
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/identity/IdentityProvider.jsm");
|
||||
|
||||
function check_provision_flow_done(provId) {
|
||||
do_check_null(IdentityProvider._provisionFlows[provId]);
|
||||
}
|
||||
|
||||
function test_begin_provisioning() {
|
||||
do_test_pending();
|
||||
|
||||
setup_provisioning(
|
||||
TEST_USER,
|
||||
function(caller) {
|
||||
// call .beginProvisioning()
|
||||
IdentityProvider.beginProvisioning(caller);
|
||||
}, function() {},
|
||||
{
|
||||
beginProvisioningCallback: function(email, duration_s) {
|
||||
do_check_eq(email, TEST_USER);
|
||||
do_check_true(duration_s > 0);
|
||||
do_check_true(duration_s <= (24 * 3600));
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test_raise_provisioning_failure() {
|
||||
do_test_pending();
|
||||
let _callerId = null;
|
||||
|
||||
setup_provisioning(
|
||||
TEST_USER,
|
||||
function(caller) {
|
||||
// call .beginProvisioning()
|
||||
_callerId = caller.id;
|
||||
IdentityProvider.beginProvisioning(caller);
|
||||
}, function(err) {
|
||||
// this should be invoked with a populated error
|
||||
do_check_neq(err, null);
|
||||
do_check_true(err.indexOf("can't authenticate this email") > -1);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
{
|
||||
beginProvisioningCallback: function(email, duration_s) {
|
||||
// raise the failure as if we can't provision this email
|
||||
IdentityProvider.raiseProvisioningFailure(_callerId, "can't authenticate this email");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function test_genkeypair_before_begin_provisioning() {
|
||||
do_test_pending();
|
||||
|
||||
setup_provisioning(
|
||||
TEST_USER,
|
||||
function(caller) {
|
||||
// call genKeyPair without beginProvisioning
|
||||
IdentityProvider.genKeyPair(caller.id);
|
||||
},
|
||||
// expect this to be called with an error
|
||||
function(err) {
|
||||
do_check_neq(err, null);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
{
|
||||
// this should not be called at all!
|
||||
genKeyPairCallback: function(pk) {
|
||||
// a test that will surely fail because we shouldn't be here.
|
||||
do_check_true(false);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function test_genkeypair() {
|
||||
do_test_pending();
|
||||
let _callerId = null;
|
||||
|
||||
setup_provisioning(
|
||||
TEST_USER,
|
||||
function(caller) {
|
||||
_callerId = caller.id;
|
||||
IdentityProvider.beginProvisioning(caller);
|
||||
},
|
||||
function(err) {
|
||||
// should not be called!
|
||||
do_check_true(false);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
{
|
||||
beginProvisioningCallback: function(email, time_s) {
|
||||
IdentityProvider.genKeyPair(_callerId);
|
||||
},
|
||||
genKeyPairCallback: function(kp) {
|
||||
do_check_neq(kp, null);
|
||||
|
||||
// yay!
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// we've already ensured that genkeypair can't be called
|
||||
// before beginProvisioning, so this test should be enough
|
||||
// to ensure full sequential call of the 3 APIs.
|
||||
function test_register_certificate_before_genkeypair() {
|
||||
do_test_pending();
|
||||
let _callerID = null;
|
||||
|
||||
setup_provisioning(
|
||||
TEST_USER,
|
||||
function(caller) {
|
||||
// do the right thing for beginProvisioning
|
||||
_callerID = caller.id;
|
||||
IdentityProvider.beginProvisioning(caller);
|
||||
},
|
||||
// expect this to be called with an error
|
||||
function(err) {
|
||||
do_check_neq(err, null);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
},
|
||||
{
|
||||
beginProvisioningCallback: function(email, duration_s) {
|
||||
// now we try to register cert but no keygen has been done
|
||||
IdentityProvider.registerCertificate(_callerID, "fake-cert");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function test_register_certificate() {
|
||||
do_test_pending();
|
||||
let _callerId = null;
|
||||
|
||||
setup_provisioning(
|
||||
TEST_USER,
|
||||
function(caller) {
|
||||
_callerId = caller.id;
|
||||
IdentityProvider.beginProvisioning(caller);
|
||||
},
|
||||
function(err) {
|
||||
// we should be cool!
|
||||
do_check_null(err);
|
||||
|
||||
// check that the cert is there
|
||||
let identity = get_idstore().fetchIdentity(TEST_USER);
|
||||
do_check_neq(identity, null);
|
||||
do_check_eq(identity.cert, "fake-cert-42");
|
||||
|
||||
do_execute_soon(function check_done() {
|
||||
// cleanup will happen after the callback is called
|
||||
check_provision_flow_done(_callerId);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
},
|
||||
{
|
||||
beginProvisioningCallback: function(email, duration_s) {
|
||||
IdentityProvider.genKeyPair(_callerId);
|
||||
},
|
||||
genKeyPairCallback: function(pk) {
|
||||
IdentityProvider.registerCertificate(_callerId, "fake-cert-42");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
function test_get_assertion_after_provision() {
|
||||
do_test_pending();
|
||||
let _callerId = null;
|
||||
|
||||
setup_provisioning(
|
||||
TEST_USER,
|
||||
function(caller) {
|
||||
_callerId = caller.id;
|
||||
IdentityProvider.beginProvisioning(caller);
|
||||
},
|
||||
function(err) {
|
||||
// we should be cool!
|
||||
do_check_null(err);
|
||||
|
||||
// check that the cert is there
|
||||
let identity = get_idstore().fetchIdentity(TEST_USER);
|
||||
do_check_neq(identity, null);
|
||||
do_check_eq(identity.cert, "fake-cert-42");
|
||||
|
||||
do_execute_soon(function check_done() {
|
||||
// cleanup will happen after the callback is called
|
||||
check_provision_flow_done(_callerId);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
},
|
||||
{
|
||||
beginProvisioningCallback: function(email, duration_s) {
|
||||
IdentityProvider.genKeyPair(_callerId);
|
||||
},
|
||||
genKeyPairCallback: function(pk) {
|
||||
IdentityProvider.registerCertificate(_callerId, "fake-cert-42");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
var TESTS = [];
|
||||
|
||||
TESTS.push(test_begin_provisioning);
|
||||
TESTS.push(test_raise_provisioning_failure);
|
||||
TESTS.push(test_genkeypair_before_begin_provisioning);
|
||||
TESTS.push(test_genkeypair);
|
||||
TESTS.push(test_register_certificate_before_genkeypair);
|
||||
TESTS.push(test_register_certificate);
|
||||
TESTS.push(test_get_assertion_after_provision);
|
||||
|
||||
TESTS.forEach(add_test);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
255
toolkit/identity/tests/unit/test_relying_party.js
Normal file
255
toolkit/identity/tests/unit/test_relying_party.js
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "RelyingParty",
|
||||
"resource://gre/modules/identity/RelyingParty.jsm");
|
||||
|
||||
function resetState() {
|
||||
get_idstore().reset();
|
||||
RelyingParty.reset();
|
||||
}
|
||||
|
||||
function test_watch_loggedin_ready() {
|
||||
do_test_pending();
|
||||
|
||||
resetState();
|
||||
|
||||
let id = TEST_USER;
|
||||
setup_test_identity(id, TEST_CERT, function() {
|
||||
let store = get_idstore();
|
||||
|
||||
// set it up so we're supposed to be logged in to TEST_URL
|
||||
store.setLoginState(TEST_URL, true, id);
|
||||
RelyingParty.watch(mock_doc(id, TEST_URL, function(action, params) {
|
||||
do_check_eq(action, 'ready');
|
||||
do_check_eq(params, undefined);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function test_watch_loggedin_login() {
|
||||
do_test_pending();
|
||||
|
||||
resetState();
|
||||
|
||||
let id = TEST_USER;
|
||||
setup_test_identity(id, TEST_CERT, function() {
|
||||
let store = get_idstore();
|
||||
|
||||
// set it up so we're supposed to be logged in to TEST_URL
|
||||
store.setLoginState(TEST_URL, true, id);
|
||||
|
||||
// check for first a login() call, then a ready() call
|
||||
RelyingParty.watch(mock_doc(null, TEST_URL, call_sequentially(
|
||||
function(action, params) {
|
||||
do_check_eq(action, 'login');
|
||||
do_check_neq(params, null);
|
||||
},
|
||||
function(action, params) {
|
||||
do_check_eq(action, 'ready');
|
||||
do_check_null(params);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
)));
|
||||
});
|
||||
}
|
||||
|
||||
function test_watch_loggedin_logout() {
|
||||
do_test_pending();
|
||||
|
||||
resetState();
|
||||
|
||||
let id = TEST_USER;
|
||||
let other_id = "otherid@foo.com";
|
||||
setup_test_identity(other_id, TEST_CERT, function() {
|
||||
setup_test_identity(id, TEST_CERT, function() {
|
||||
let store = get_idstore();
|
||||
|
||||
// set it up so we're supposed to be logged in to TEST_URL
|
||||
// with id, not other_id
|
||||
store.setLoginState(TEST_URL, true, id);
|
||||
|
||||
// this should cause a login with an assertion for id,
|
||||
// not for other_id
|
||||
RelyingParty.watch(mock_doc(other_id, TEST_URL, call_sequentially(
|
||||
function(action, params) {
|
||||
do_check_eq(action, 'login');
|
||||
do_check_neq(params, null);
|
||||
},
|
||||
function(action, params) {
|
||||
do_check_eq(action, 'ready');
|
||||
do_check_null(params);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
)));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function test_watch_notloggedin_ready() {
|
||||
do_test_pending();
|
||||
|
||||
resetState();
|
||||
|
||||
RelyingParty.watch(mock_doc(null, TEST_URL, function(action, params) {
|
||||
do_check_eq(action, 'ready');
|
||||
do_check_eq(params, undefined);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}));
|
||||
}
|
||||
|
||||
function test_watch_notloggedin_logout() {
|
||||
do_test_pending();
|
||||
|
||||
resetState();
|
||||
|
||||
RelyingParty.watch(mock_doc(TEST_USER, TEST_URL, call_sequentially(
|
||||
function(action, params) {
|
||||
do_check_eq(action, 'logout');
|
||||
do_check_eq(params, undefined);
|
||||
|
||||
let store = get_idstore();
|
||||
do_check_null(store.getLoginState(TEST_URL));
|
||||
},
|
||||
function(action, params) {
|
||||
do_check_eq(action, 'ready');
|
||||
do_check_eq(params, undefined);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}
|
||||
)));
|
||||
}
|
||||
|
||||
function test_request() {
|
||||
do_test_pending();
|
||||
|
||||
// set up a watch, to be consistent
|
||||
let mockedDoc = mock_doc(null, TEST_URL, function(action, params) {
|
||||
// this isn't going to be called for now
|
||||
// XXX but it is called - is that bad?
|
||||
});
|
||||
|
||||
RelyingParty.watch(mockedDoc);
|
||||
|
||||
// be ready for the UX identity-request notification
|
||||
makeObserver("identity-request", function (aSubject, aTopic, aData) {
|
||||
do_check_neq(aSubject, null);
|
||||
|
||||
do_check_eq(aSubject.wrappedJSObject.rpId, mockedDoc.id);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
RelyingParty.request(mockedDoc.id, {});
|
||||
}
|
||||
|
||||
/*
|
||||
* ensure the forceAuthentication param can be passed through
|
||||
*/
|
||||
function test_request_forceAuthentication() {
|
||||
do_test_pending();
|
||||
|
||||
let mockedDoc = mock_doc(null, TEST_URL, function(action, params) {});
|
||||
|
||||
RelyingParty.watch(mockedDoc);
|
||||
|
||||
makeObserver("identity-request", function(aSubject, aTopic, aData) {
|
||||
do_check_eq(aSubject.wrappedJSObject.rpId, mockedDoc.id);
|
||||
do_check_eq(aSubject.wrappedJSObject.forceAuthentication, true);
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
RelyingParty.request(mockedDoc.id, {forceAuthentication: true});
|
||||
}
|
||||
|
||||
/*
|
||||
* ensure the issuer can be forced
|
||||
*/
|
||||
function test_request_forceIssuer() {
|
||||
do_test_pending();
|
||||
|
||||
let mockedDoc = mock_doc(null, TEST_URL, function(action, params) {});
|
||||
|
||||
RelyingParty.watch(mockedDoc);
|
||||
|
||||
makeObserver("identity-request", function(aSubject, aTopic, aData) {
|
||||
do_check_eq(aSubject.wrappedJSObject.rpId, mockedDoc.id);
|
||||
do_check_eq(aSubject.wrappedJSObject.issuer, "https://ozten.co.uk");
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
RelyingParty.request(mockedDoc.id, {issuer: "https://ozten.co.uk"});
|
||||
}
|
||||
function test_logout() {
|
||||
do_test_pending();
|
||||
|
||||
resetState();
|
||||
|
||||
let id = TEST_USER;
|
||||
setup_test_identity(id, TEST_CERT, function() {
|
||||
let store = get_idstore();
|
||||
|
||||
// set it up so we're supposed to be logged in to TEST_URL
|
||||
store.setLoginState(TEST_URL, true, id);
|
||||
|
||||
let doLogout;
|
||||
let mockedDoc = mock_doc(id, TEST_URL, call_sequentially(
|
||||
function(action, params) {
|
||||
do_check_eq(action, 'ready');
|
||||
do_check_eq(params, undefined);
|
||||
|
||||
do_timeout(100, doLogout);
|
||||
},
|
||||
function(action, params) {
|
||||
do_check_eq(action, 'logout');
|
||||
do_check_eq(params, undefined);
|
||||
},
|
||||
function(action, params) {
|
||||
do_check_eq(action, 'ready');
|
||||
do_check_eq(params, undefined);
|
||||
|
||||
do_test_finished();
|
||||
run_next_test();
|
||||
}));
|
||||
|
||||
doLogout = function() {
|
||||
RelyingParty.logout(mockedDoc.id);
|
||||
do_check_false(store.getLoginState(TEST_URL).isLoggedIn);
|
||||
do_check_eq(store.getLoginState(TEST_URL).email, TEST_USER);
|
||||
};
|
||||
|
||||
RelyingParty.watch(mockedDoc);
|
||||
});
|
||||
}
|
||||
|
||||
var TESTS = [
|
||||
test_watch_loggedin_ready,
|
||||
test_watch_loggedin_login,
|
||||
test_watch_loggedin_logout,
|
||||
test_watch_notloggedin_ready,
|
||||
test_watch_notloggedin_logout,
|
||||
test_request,
|
||||
test_request_forceAuthentication,
|
||||
test_request_forceIssuer,
|
||||
test_logout,
|
||||
];
|
||||
|
||||
TESTS.forEach(add_test);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
64
toolkit/identity/tests/unit/test_store.js
Normal file
64
toolkit/identity/tests/unit/test_store.js
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "IDService",
|
||||
"resource://gre/modules/identity/Identity.jsm",
|
||||
"IdentityService");
|
||||
|
||||
function test_id_store() {
|
||||
// XXX - this is ugly, peaking in like this into IDService
|
||||
// probably should instantiate our own.
|
||||
var store = get_idstore();
|
||||
|
||||
// try adding an identity
|
||||
store.addIdentity(TEST_USER, TEST_PRIVKEY, TEST_CERT);
|
||||
do_check_neq(store.getIdentities()[TEST_USER], null);
|
||||
do_check_eq(store.getIdentities()[TEST_USER].cert, TEST_CERT);
|
||||
|
||||
// does fetch identity work?
|
||||
do_check_neq(store.fetchIdentity(TEST_USER), null);
|
||||
do_check_eq(store.fetchIdentity(TEST_USER).cert, TEST_CERT);
|
||||
|
||||
// clear the cert should keep the identity but not the cert
|
||||
store.clearCert(TEST_USER);
|
||||
do_check_neq(store.getIdentities()[TEST_USER], null);
|
||||
do_check_null(store.getIdentities()[TEST_USER].cert);
|
||||
|
||||
// remove it should remove everything
|
||||
store.removeIdentity(TEST_USER);
|
||||
do_check_eq(store.getIdentities()[TEST_USER], undefined);
|
||||
|
||||
// act like we're logged in to TEST_URL
|
||||
store.setLoginState(TEST_URL, true, TEST_USER);
|
||||
do_check_neq(store.getLoginState(TEST_URL), null);
|
||||
do_check_true(store.getLoginState(TEST_URL).isLoggedIn);
|
||||
do_check_eq(store.getLoginState(TEST_URL).email, TEST_USER);
|
||||
|
||||
// log out
|
||||
store.setLoginState(TEST_URL, false, TEST_USER);
|
||||
do_check_neq(store.getLoginState(TEST_URL), null);
|
||||
do_check_false(store.getLoginState(TEST_URL).isLoggedIn);
|
||||
|
||||
// email is still set
|
||||
do_check_eq(store.getLoginState(TEST_URL).email, TEST_USER);
|
||||
|
||||
// not logged into other site
|
||||
do_check_null(store.getLoginState(TEST_URL2));
|
||||
|
||||
// clear login state
|
||||
store.clearLoginState(TEST_URL);
|
||||
do_check_null(store.getLoginState(TEST_URL));
|
||||
do_check_null(store.getLoginState(TEST_URL2));
|
||||
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
var TESTS = [test_id_store, ];
|
||||
|
||||
TESTS.forEach(add_test);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
90
toolkit/identity/tests/unit/test_well-known.js
Normal file
90
toolkit/identity/tests/unit/test_well-known.js
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "IDService",
|
||||
"resource://gre/modules/identity/Identity.jsm",
|
||||
"IdentityService");
|
||||
|
||||
const WELL_KNOWN_PATH = "/.well-known/browserid";
|
||||
|
||||
var SERVER_PORT = 8080;
|
||||
|
||||
// valid IDP
|
||||
function test_well_known_1() {
|
||||
do_test_pending();
|
||||
|
||||
let server = new HttpServer();
|
||||
server.registerFile(WELL_KNOWN_PATH, do_get_file("data/idp_1" + WELL_KNOWN_PATH));
|
||||
server.start(SERVER_PORT);
|
||||
let hostPort = "localhost:" + SERVER_PORT;
|
||||
|
||||
function check_well_known(aErr, aCallbackObj) {
|
||||
do_check_null(aErr);
|
||||
do_check_eq(aCallbackObj.domain, hostPort);
|
||||
let idpParams = aCallbackObj.idpParams;
|
||||
do_check_eq(idpParams['public-key'].algorithm, "RS");
|
||||
do_check_eq(idpParams.authentication, "/browserid/sign_in.html");
|
||||
do_check_eq(idpParams.provisioning, "/browserid/provision.html");
|
||||
|
||||
do_test_finished();
|
||||
server.stop(run_next_test);
|
||||
}
|
||||
|
||||
IDService._fetchWellKnownFile(hostPort, check_well_known, "http");
|
||||
}
|
||||
|
||||
// valid domain, non-exixtent browserid file
|
||||
function test_well_known_404() {
|
||||
do_test_pending();
|
||||
|
||||
let server = new HttpServer();
|
||||
// Don't register the well-known file
|
||||
// Change ports to avoid HTTP caching
|
||||
SERVER_PORT++;
|
||||
server.start(SERVER_PORT);
|
||||
|
||||
let hostPort = "localhost:" + SERVER_PORT;
|
||||
|
||||
function check_well_known_404(aErr, aCallbackObj) {
|
||||
do_check_eq("Error", aErr);
|
||||
do_check_eq(undefined, aCallbackObj);
|
||||
do_test_finished();
|
||||
server.stop(run_next_test);
|
||||
}
|
||||
|
||||
IDService._fetchWellKnownFile(hostPort, check_well_known_404, "http");
|
||||
}
|
||||
|
||||
// valid domain, invalid browserid file (no "provisioning" member)
|
||||
function test_well_known_invalid_1() {
|
||||
do_test_pending();
|
||||
|
||||
let server = new HttpServer();
|
||||
server.registerFile(WELL_KNOWN_PATH, do_get_file("data/idp_invalid_1" + WELL_KNOWN_PATH));
|
||||
// Change ports to avoid HTTP caching
|
||||
SERVER_PORT++;
|
||||
server.start(SERVER_PORT);
|
||||
|
||||
let hostPort = "localhost:" + SERVER_PORT;
|
||||
|
||||
function check_well_known_invalid_1(aErr, aCallbackObj) {
|
||||
// check for an error message
|
||||
do_check_true(aErr && aErr.length > 0);
|
||||
do_check_eq(undefined, aCallbackObj);
|
||||
do_test_finished();
|
||||
server.stop(run_next_test);
|
||||
}
|
||||
|
||||
IDService._fetchWellKnownFile(hostPort, check_well_known_invalid_1, "http");
|
||||
}
|
||||
|
||||
var TESTS = [test_well_known_1, test_well_known_404, test_well_known_invalid_1];
|
||||
|
||||
TESTS.forEach(add_test);
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
24
toolkit/identity/tests/unit/xpcshell.ini
Normal file
24
toolkit/identity/tests/unit/xpcshell.ini
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
[DEFAULT]
|
||||
head = head_identity.js
|
||||
tail = tail_identity.js
|
||||
skip-if = (appname != "b2g" || toolkit == 'gonk')
|
||||
support-files =
|
||||
data/idp_1/.well-known/browserid
|
||||
data/idp_invalid_1/.well-known/browserid
|
||||
|
||||
# Test load modules first so syntax failures are caught early.
|
||||
[test_load_modules.js]
|
||||
[test_minimalidentity.js]
|
||||
[test_firefox_accounts.js]
|
||||
|
||||
[test_identity_utils.js]
|
||||
[test_log_utils.js]
|
||||
[test_authentication.js]
|
||||
[test_crypto_service.js]
|
||||
[test_identity.js]
|
||||
[test_jwcrypto.js]
|
||||
[test_observer_topics.js]
|
||||
[test_provisioning.js]
|
||||
[test_relying_party.js]
|
||||
[test_store.js]
|
||||
[test_well-known.js]
|
||||
Loading…
Add table
Add a link
Reference in a new issue