|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 "use strict"; |
|
6 |
|
7 this.EXPORTED_SYMBOLS = [ |
|
8 "btoa", // It comes from a module import. |
|
9 "encryptPayload", |
|
10 "ensureLegacyIdentityManager", |
|
11 "setBasicCredentials", |
|
12 "makeIdentityConfig", |
|
13 "configureFxAccountIdentity", |
|
14 "configureIdentity", |
|
15 "SyncTestingInfrastructure", |
|
16 "waitForZeroTimer", |
|
17 "Promise", // from a module import |
|
18 "add_identity_test", |
|
19 ]; |
|
20 |
|
21 const {utils: Cu} = Components; |
|
22 |
|
23 Cu.import("resource://services-sync/status.js"); |
|
24 Cu.import("resource://services-sync/identity.js"); |
|
25 Cu.import("resource://services-common/utils.js"); |
|
26 Cu.import("resource://services-crypto/utils.js"); |
|
27 Cu.import("resource://services-sync/util.js"); |
|
28 Cu.import("resource://services-sync/browserid_identity.js"); |
|
29 Cu.import("resource://testing-common/services-common/logging.js"); |
|
30 Cu.import("resource://testing-common/services/sync/fakeservices.js"); |
|
31 Cu.import("resource://gre/modules/FxAccounts.jsm"); |
|
32 Cu.import("resource://gre/modules/FxAccountsCommon.js"); |
|
33 Cu.import("resource://gre/modules/Promise.jsm"); |
|
34 |
|
35 /** |
|
36 * First wait >100ms (nsITimers can take up to that much time to fire, so |
|
37 * we can account for the timer in delayedAutoconnect) and then two event |
|
38 * loop ticks (to account for the Utils.nextTick() in autoConnect). |
|
39 */ |
|
40 this.waitForZeroTimer = function waitForZeroTimer(callback) { |
|
41 let ticks = 2; |
|
42 function wait() { |
|
43 if (ticks) { |
|
44 ticks -= 1; |
|
45 CommonUtils.nextTick(wait); |
|
46 return; |
|
47 } |
|
48 callback(); |
|
49 } |
|
50 CommonUtils.namedTimer(wait, 150, {}, "timer"); |
|
51 } |
|
52 |
|
53 /** |
|
54 * Ensure Sync is configured with the "legacy" identity provider. |
|
55 */ |
|
56 this.ensureLegacyIdentityManager = function() { |
|
57 let ns = {}; |
|
58 Cu.import("resource://services-sync/service.js", ns); |
|
59 |
|
60 Status.__authManager = ns.Service.identity = new IdentityManager(); |
|
61 ns.Service._clusterManager = ns.Service.identity.createClusterManager(ns.Service); |
|
62 } |
|
63 |
|
64 this.setBasicCredentials = |
|
65 function setBasicCredentials(username, password, syncKey) { |
|
66 let ns = {}; |
|
67 Cu.import("resource://services-sync/service.js", ns); |
|
68 |
|
69 let auth = ns.Service.identity; |
|
70 auth.username = username; |
|
71 auth.basicPassword = password; |
|
72 auth.syncKey = syncKey; |
|
73 } |
|
74 |
|
75 // Return an identity configuration suitable for testing with our identity |
|
76 // providers. |overrides| can specify overrides for any default values. |
|
77 this.makeIdentityConfig = function(overrides) { |
|
78 // first setup the defaults. |
|
79 let result = { |
|
80 // Username used in both fxaccount and sync identity configs. |
|
81 username: "foo", |
|
82 // fxaccount specific credentials. |
|
83 fxaccount: { |
|
84 user: { |
|
85 assertion: 'assertion', |
|
86 email: 'email', |
|
87 kA: 'kA', |
|
88 kB: 'kB', |
|
89 sessionToken: 'sessionToken', |
|
90 uid: 'user_uid', |
|
91 verified: true, |
|
92 }, |
|
93 token: { |
|
94 endpoint: Svc.Prefs.get("tokenServerURI"), |
|
95 duration: 300, |
|
96 id: "id", |
|
97 key: "key", |
|
98 // uid will be set to the username. |
|
99 } |
|
100 }, |
|
101 sync: { |
|
102 // username will come from the top-level username |
|
103 password: "whatever", |
|
104 syncKey: "abcdeabcdeabcdeabcdeabcdea", |
|
105 } |
|
106 }; |
|
107 |
|
108 // Now handle any specified overrides. |
|
109 if (overrides) { |
|
110 if (overrides.username) { |
|
111 result.username = overrides.username; |
|
112 } |
|
113 if (overrides.sync) { |
|
114 // TODO: allow just some attributes to be specified |
|
115 result.sync = overrides.sync; |
|
116 } |
|
117 if (overrides.fxaccount) { |
|
118 // TODO: allow just some attributes to be specified |
|
119 result.fxaccount = overrides.fxaccount; |
|
120 } |
|
121 } |
|
122 return result; |
|
123 } |
|
124 |
|
125 // Configure an instance of an FxAccount identity provider with the specified |
|
126 // config (or the default config if not specified). |
|
127 this.configureFxAccountIdentity = function(authService, |
|
128 config = makeIdentityConfig()) { |
|
129 let MockInternal = {}; |
|
130 let fxa = new FxAccounts(MockInternal); |
|
131 |
|
132 // until we get better test infrastructure for bid_identity, we set the |
|
133 // signedin user's "email" to the username, simply as many tests rely on this. |
|
134 config.fxaccount.user.email = config.username; |
|
135 fxa.internal.currentAccountState.signedInUser = { |
|
136 version: DATA_FORMAT_VERSION, |
|
137 accountData: config.fxaccount.user |
|
138 }; |
|
139 fxa.internal.currentAccountState.getCertificate = function(data, keyPair, mustBeValidUntil) { |
|
140 this.cert = { |
|
141 validUntil: fxa.internal.now() + CERT_LIFETIME, |
|
142 cert: "certificate", |
|
143 }; |
|
144 return Promise.resolve(this.cert.cert); |
|
145 }; |
|
146 |
|
147 let mockTSC = { // TokenServerClient |
|
148 getTokenFromBrowserIDAssertion: function(uri, assertion, cb) { |
|
149 config.fxaccount.token.uid = config.username; |
|
150 cb(null, config.fxaccount.token); |
|
151 }, |
|
152 }; |
|
153 authService._fxaService = fxa; |
|
154 authService._tokenServerClient = mockTSC; |
|
155 // Set the "account" of the browserId manager to be the "email" of the |
|
156 // logged in user of the mockFXA service. |
|
157 authService._signedInUser = fxa.internal.currentAccountState.signedInUser.accountData; |
|
158 authService._account = config.fxaccount.user.email; |
|
159 } |
|
160 |
|
161 this.configureIdentity = function(identityOverrides) { |
|
162 let config = makeIdentityConfig(identityOverrides); |
|
163 let ns = {}; |
|
164 Cu.import("resource://services-sync/service.js", ns); |
|
165 |
|
166 if (ns.Service.identity instanceof BrowserIDManager) { |
|
167 // do the FxAccounts thang... |
|
168 configureFxAccountIdentity(ns.Service.identity, config); |
|
169 return ns.Service.identity.initializeWithCurrentIdentity().then(() => { |
|
170 // need to wait until this identity manager is readyToAuthenticate. |
|
171 return ns.Service.identity.whenReadyToAuthenticate.promise; |
|
172 }); |
|
173 } |
|
174 // old style identity provider. |
|
175 setBasicCredentials(config.username, config.sync.password, config.sync.syncKey); |
|
176 let deferred = Promise.defer(); |
|
177 deferred.resolve(); |
|
178 return deferred.promise; |
|
179 } |
|
180 |
|
181 this.SyncTestingInfrastructure = function (server, username, password, syncKey) { |
|
182 let ns = {}; |
|
183 Cu.import("resource://services-sync/service.js", ns); |
|
184 |
|
185 ensureLegacyIdentityManager(); |
|
186 let config = makeIdentityConfig(); |
|
187 // XXX - hacks for the sync identity provider. |
|
188 if (username) |
|
189 config.username = username; |
|
190 if (password) |
|
191 config.sync.password = password; |
|
192 if (syncKey) |
|
193 config.sync.syncKey = syncKey; |
|
194 let cb = Async.makeSpinningCallback(); |
|
195 configureIdentity(config).then(cb, cb); |
|
196 cb.wait(); |
|
197 |
|
198 let i = server.identity; |
|
199 let uri = i.primaryScheme + "://" + i.primaryHost + ":" + |
|
200 i.primaryPort + "/"; |
|
201 |
|
202 ns.Service.serverURL = uri; |
|
203 ns.Service.clusterURL = uri; |
|
204 |
|
205 this.logStats = initTestLogging(); |
|
206 this.fakeFilesystem = new FakeFilesystemService({}); |
|
207 this.fakeGUIDService = new FakeGUIDService(); |
|
208 this.fakeCryptoService = new FakeCryptoService(); |
|
209 } |
|
210 |
|
211 /** |
|
212 * Turn WBO cleartext into fake "encrypted" payload as it goes over the wire. |
|
213 */ |
|
214 this.encryptPayload = function encryptPayload(cleartext) { |
|
215 if (typeof cleartext == "object") { |
|
216 cleartext = JSON.stringify(cleartext); |
|
217 } |
|
218 |
|
219 return { |
|
220 ciphertext: cleartext, // ciphertext == cleartext with fake crypto |
|
221 IV: "irrelevant", |
|
222 hmac: fakeSHA256HMAC(cleartext, CryptoUtils.makeHMACKey("")), |
|
223 }; |
|
224 } |
|
225 |
|
226 // This helper can be used instead of 'add_test' or 'add_task' to run the |
|
227 // specified test function twice - once with the old-style sync identity |
|
228 // manager and once with the new-style BrowserID identity manager, to ensure |
|
229 // it works in both cases. |
|
230 // |
|
231 // * The test itself should be passed as 'test' - ie, test code will generally |
|
232 // pass |this|. |
|
233 // * The test function is a regular test function - although note that it must |
|
234 // be a generator - async operations should yield them, and run_next_test |
|
235 // mustn't be called. |
|
236 this.add_identity_test = function(test, testFunction) { |
|
237 function note(what) { |
|
238 let msg = "running test " + testFunction.name + " with " + what + " identity manager"; |
|
239 test._log("test_info", |
|
240 {_message: "TEST-INFO | | " + msg + "\n"}); |
|
241 } |
|
242 let ns = {}; |
|
243 Cu.import("resource://services-sync/service.js", ns); |
|
244 // one task for the "old" identity manager. |
|
245 test.add_task(function() { |
|
246 note("sync"); |
|
247 let oldIdentity = Status._authManager; |
|
248 ensureLegacyIdentityManager(); |
|
249 yield testFunction(); |
|
250 Status.__authManager = ns.Service.identity = oldIdentity; |
|
251 }); |
|
252 // another task for the FxAccounts identity manager. |
|
253 test.add_task(function() { |
|
254 note("FxAccounts"); |
|
255 let oldIdentity = Status._authManager; |
|
256 Status.__authManager = ns.Service.identity = new BrowserIDManager(); |
|
257 yield testFunction(); |
|
258 Status.__authManager = ns.Service.identity = oldIdentity; |
|
259 }); |
|
260 } |