mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1127638 - Provide a way to get an OAuth token for a set of desired scopes for the currently logged in user r=markh
This commit is contained in:
parent
e15c2cd772
commit
3e89e578f1
@ -1756,6 +1756,12 @@ pref("identity.fxaccounts.remote.signin.uri", "https://accounts.firefox.com/sign
|
|||||||
// "identity.fxaccounts.remote.signup.uri" pref.
|
// "identity.fxaccounts.remote.signup.uri" pref.
|
||||||
pref("identity.fxaccounts.settings.uri", "https://accounts.firefox.com/settings");
|
pref("identity.fxaccounts.settings.uri", "https://accounts.firefox.com/settings");
|
||||||
|
|
||||||
|
// The remote URL of the FxA Profile Server
|
||||||
|
pref("identity.fxaccounts.remote.profile.uri", "https://profile.accounts.firefox.com/v1");
|
||||||
|
|
||||||
|
// The remote URL of the FxA OAuth Server
|
||||||
|
pref("identity.fxaccounts.remote.oauth.uri", "https://oauth.accounts.firefox.com/v1");
|
||||||
|
|
||||||
// Migrate any existing Firefox Account data from the default profile to the
|
// Migrate any existing Firefox Account data from the default profile to the
|
||||||
// Developer Edition profile.
|
// Developer Edition profile.
|
||||||
#ifdef MOZ_DEV_EDITION
|
#ifdef MOZ_DEV_EDITION
|
||||||
|
@ -23,6 +23,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsClient",
|
|||||||
XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto",
|
XPCOMUtils.defineLazyModuleGetter(this, "jwcrypto",
|
||||||
"resource://gre/modules/identity/jwcrypto.jsm");
|
"resource://gre/modules/identity/jwcrypto.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "FxAccountsOAuthGrantClient",
|
||||||
|
"resource://gre/modules/FxAccountsOAuthGrantClient.jsm");
|
||||||
|
|
||||||
// All properties exposed by the public FxAccounts API.
|
// All properties exposed by the public FxAccounts API.
|
||||||
let publicProperties = [
|
let publicProperties = [
|
||||||
"accountStatus",
|
"accountStatus",
|
||||||
@ -32,6 +35,7 @@ let publicProperties = [
|
|||||||
"getAssertion",
|
"getAssertion",
|
||||||
"getKeys",
|
"getKeys",
|
||||||
"getSignedInUser",
|
"getSignedInUser",
|
||||||
|
"getOAuthToken",
|
||||||
"loadAndPoll",
|
"loadAndPoll",
|
||||||
"localtimeOffsetMsec",
|
"localtimeOffsetMsec",
|
||||||
"now",
|
"now",
|
||||||
@ -904,6 +908,28 @@ FxAccountsInternal.prototype = {
|
|||||||
newQueryPortion += "email=" + encodeURIComponent(accountData.email);
|
newQueryPortion += "email=" + encodeURIComponent(accountData.email);
|
||||||
return url + newQueryPortion;
|
return url + newQueryPortion;
|
||||||
}).then(result => currentState.resolve(result));
|
}).then(result => currentState.resolve(result));
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get an OAuth token for the user
|
||||||
|
*/
|
||||||
|
getOAuthToken: function (options = {}) {
|
||||||
|
log.debug("getOAuthToken enter");
|
||||||
|
|
||||||
|
if (!options.scope) {
|
||||||
|
throw new Error("Missing 'scope' option");
|
||||||
|
}
|
||||||
|
|
||||||
|
let oAuthURL = Services.urlFormatter.formatURLPref("identity.fxaccounts.remote.oauth.uri");
|
||||||
|
|
||||||
|
let client = options.client || new FxAccountsOAuthGrantClient({
|
||||||
|
serverURL: oAuthURL,
|
||||||
|
client_id: FX_OAUTH_CLIENT_ID
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.getAssertion(oAuthURL)
|
||||||
|
.then(assertion => client.getTokenFromAssertion(assertion, options.scope))
|
||||||
|
.then(result => result.access_token);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -94,6 +94,9 @@ exports.ON_FXA_UPDATE_NOTIFICATION = "fxaccounts:update";
|
|||||||
exports.UI_REQUEST_SIGN_IN_FLOW = "signInFlow";
|
exports.UI_REQUEST_SIGN_IN_FLOW = "signInFlow";
|
||||||
exports.UI_REQUEST_REFRESH_AUTH = "refreshAuthentication";
|
exports.UI_REQUEST_REFRESH_AUTH = "refreshAuthentication";
|
||||||
|
|
||||||
|
// The OAuth client ID for Firefox Desktop
|
||||||
|
exports.FX_OAUTH_CLIENT_ID = "5882386c6d801776";
|
||||||
|
|
||||||
// Server errno.
|
// Server errno.
|
||||||
// From https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#response-format
|
// From https://github.com/mozilla/fxa-auth-server/blob/master/docs/api.md#response-format
|
||||||
exports.ERRNO_ACCOUNT_ALREADY_EXISTS = 101;
|
exports.ERRNO_ACCOUNT_ALREADY_EXISTS = 101;
|
||||||
|
215
services/fxaccounts/FxAccountsOAuthGrantClient.jsm
Normal file
215
services/fxaccounts/FxAccountsOAuthGrantClient.jsm
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
/* 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/. */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Firefox Accounts OAuth Grant Client allows clients to obtain
|
||||||
|
* an OAuth token from a BrowserID assertion. Only certain client
|
||||||
|
* IDs support this privilage.
|
||||||
|
*/
|
||||||
|
|
||||||
|
this.EXPORTED_SYMBOLS = ["FxAccountsOAuthGrantClient", "FxAccountsOAuthGrantClientError"];
|
||||||
|
|
||||||
|
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/Promise.jsm");
|
||||||
|
Cu.import("resource://gre/modules/Log.jsm");
|
||||||
|
Cu.import("resource://gre/modules/FxAccountsCommon.js");
|
||||||
|
Cu.import("resource://services-common/rest.js");
|
||||||
|
|
||||||
|
Cu.importGlobalProperties(["URL"]);
|
||||||
|
|
||||||
|
const AUTH_ENDPOINT = "/authorization";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new FxAccountsOAuthClient for browser some service.
|
||||||
|
*
|
||||||
|
* @param {Object} options Options
|
||||||
|
* @param {Object} options.parameters
|
||||||
|
* @param {String} options.parameters.client_id
|
||||||
|
* OAuth id returned from client registration
|
||||||
|
* @param {String} options.parameters.serverURL
|
||||||
|
* The FxA OAuth server URL
|
||||||
|
* @param [authorizationEndpoint] {String}
|
||||||
|
* Optional authorization endpoint for the OAuth server
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
this.FxAccountsOAuthGrantClient = function(options) {
|
||||||
|
|
||||||
|
this._validateOptions(options);
|
||||||
|
this.parameters = options;
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.serverURL = new URL(this.parameters.serverURL);
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error("Invalid 'serverURL'");
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("FxAccountsOAuthGrantClient Initialized");
|
||||||
|
};
|
||||||
|
|
||||||
|
this.FxAccountsOAuthGrantClient.prototype = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves an OAuth access token for the signed in user
|
||||||
|
*
|
||||||
|
* @param {Object} assertion BrowserID assertion
|
||||||
|
* @param {String} scope OAuth scope
|
||||||
|
* @return Promise
|
||||||
|
* Resolves: {Object} Object with access_token property
|
||||||
|
*/
|
||||||
|
getTokenFromAssertion: function (assertion, scope) {
|
||||||
|
if (!assertion) {
|
||||||
|
throw new Error("Missing 'assertion' parameter");
|
||||||
|
}
|
||||||
|
if (!scope) {
|
||||||
|
throw new Error("Missing 'scope' parameter");
|
||||||
|
}
|
||||||
|
let params = {
|
||||||
|
scope: scope,
|
||||||
|
client_id: this.parameters.client_id,
|
||||||
|
assertion: assertion,
|
||||||
|
response_type: "token"
|
||||||
|
};
|
||||||
|
|
||||||
|
return this._createRequest(AUTH_ENDPOINT, "POST", params);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the required FxA OAuth parameters
|
||||||
|
*
|
||||||
|
* @param options {Object}
|
||||||
|
* OAuth client options
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_validateOptions: function (options) {
|
||||||
|
if (!options) {
|
||||||
|
throw new Error("Missing configuration options");
|
||||||
|
}
|
||||||
|
|
||||||
|
["serverURL", "client_id"].forEach(option => {
|
||||||
|
if (!options[option]) {
|
||||||
|
throw new Error("Missing '" + option + "' parameter");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for making remote requests.
|
||||||
|
*/
|
||||||
|
_Request: RESTRequest,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remote request helper
|
||||||
|
*
|
||||||
|
* @param {String} path
|
||||||
|
* Profile server path, i.e "/profile".
|
||||||
|
* @param {String} [method]
|
||||||
|
* Type of request, i.e "GET".
|
||||||
|
* @return Promise
|
||||||
|
* Resolves: {Object} Successful response from the Profile server.
|
||||||
|
* Rejects: {FxAccountsOAuthGrantClientError} Profile client error.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_createRequest: function(path, method = "POST", params) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let profileDataUrl = this.serverURL + path;
|
||||||
|
let request = new this._Request(profileDataUrl);
|
||||||
|
method = method.toUpperCase();
|
||||||
|
|
||||||
|
request.setHeader("Accept", "application/json");
|
||||||
|
request.setHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
|
request.onComplete = function (error) {
|
||||||
|
if (error) {
|
||||||
|
return reject(new FxAccountsOAuthGrantClientError({
|
||||||
|
error: ERROR_NETWORK,
|
||||||
|
errno: ERRNO_NETWORK,
|
||||||
|
message: error.toString(),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
let body = null;
|
||||||
|
try {
|
||||||
|
body = JSON.parse(request.response.body);
|
||||||
|
} catch (e) {
|
||||||
|
return reject(new FxAccountsOAuthGrantClientError({
|
||||||
|
error: ERROR_PARSE,
|
||||||
|
errno: ERRNO_PARSE,
|
||||||
|
code: request.response.status,
|
||||||
|
message: request.response.body,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// "response.success" means status code is 200
|
||||||
|
if (request.response.success) {
|
||||||
|
return resolve(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
return reject(new FxAccountsOAuthGrantClientError(body));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (method === "POST") {
|
||||||
|
request.post(params);
|
||||||
|
} else {
|
||||||
|
// method not supported
|
||||||
|
return reject(new FxAccountsOAuthGrantClientError({
|
||||||
|
error: ERROR_NETWORK,
|
||||||
|
errno: ERRNO_NETWORK,
|
||||||
|
code: ERROR_CODE_METHOD_NOT_ALLOWED,
|
||||||
|
message: ERROR_MSG_METHOD_NOT_ALLOWED,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalized profile client errors
|
||||||
|
* @param {Object} [details]
|
||||||
|
* Error details object
|
||||||
|
* @param {number} [details.code]
|
||||||
|
* Error code
|
||||||
|
* @param {number} [details.errno]
|
||||||
|
* Error number
|
||||||
|
* @param {String} [details.error]
|
||||||
|
* Error description
|
||||||
|
* @param {String|null} [details.message]
|
||||||
|
* Error message
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
this.FxAccountsOAuthGrantClientError = function(details) {
|
||||||
|
details = details || {};
|
||||||
|
|
||||||
|
this.name = "FxAccountsOAuthGrantClientError";
|
||||||
|
this.code = details.code || null;
|
||||||
|
this.errno = details.errno || ERRNO_UNKNOWN_ERROR;
|
||||||
|
this.error = details.error || ERROR_UNKNOWN;
|
||||||
|
this.message = details.message || null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns error object properties
|
||||||
|
*
|
||||||
|
* @returns {{name: *, code: *, errno: *, error: *, message: *}}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
FxAccountsOAuthGrantClientError.prototype._toStringFields = function() {
|
||||||
|
return {
|
||||||
|
name: this.name,
|
||||||
|
code: this.code,
|
||||||
|
errno: this.errno,
|
||||||
|
error: this.error,
|
||||||
|
message: this.message,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String representation of a oauth grant client error
|
||||||
|
*
|
||||||
|
* @returns {String}
|
||||||
|
*/
|
||||||
|
FxAccountsOAuthGrantClientError.prototype.toString = function() {
|
||||||
|
return this.name + "(" + JSON.stringify(this._toStringFields()) + ")";
|
||||||
|
};
|
@ -13,6 +13,7 @@ EXTRA_JS_MODULES += [
|
|||||||
'FxAccountsClient.jsm',
|
'FxAccountsClient.jsm',
|
||||||
'FxAccountsCommon.js',
|
'FxAccountsCommon.js',
|
||||||
'FxAccountsOAuthClient.jsm',
|
'FxAccountsOAuthClient.jsm',
|
||||||
|
'FxAccountsOAuthGrantClient.jsm',
|
||||||
'FxAccountsProfileClient.jsm',
|
'FxAccountsProfileClient.jsm',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ Cu.import("resource://gre/modules/Services.jsm");
|
|||||||
Cu.import("resource://gre/modules/FxAccounts.jsm");
|
Cu.import("resource://gre/modules/FxAccounts.jsm");
|
||||||
Cu.import("resource://gre/modules/FxAccountsClient.jsm");
|
Cu.import("resource://gre/modules/FxAccountsClient.jsm");
|
||||||
Cu.import("resource://gre/modules/FxAccountsCommon.js");
|
Cu.import("resource://gre/modules/FxAccountsCommon.js");
|
||||||
|
Cu.import("resource://gre/modules/FxAccountsOAuthGrantClient.jsm");
|
||||||
Cu.import("resource://gre/modules/Promise.jsm");
|
Cu.import("resource://gre/modules/Promise.jsm");
|
||||||
Cu.import("resource://gre/modules/Log.jsm");
|
Cu.import("resource://gre/modules/Log.jsm");
|
||||||
|
|
||||||
@ -26,6 +27,11 @@ log.level = Log.Level.Debug;
|
|||||||
// See verbose logging from FxAccounts.jsm
|
// See verbose logging from FxAccounts.jsm
|
||||||
Services.prefs.setCharPref("identity.fxaccounts.loglevel", "DEBUG");
|
Services.prefs.setCharPref("identity.fxaccounts.loglevel", "DEBUG");
|
||||||
|
|
||||||
|
// The oauth server is mocked, but set these prefs to pass param checks
|
||||||
|
Services.prefs.setCharPref("identity.fxaccounts.remote.oauth.uri", "https://example.com/v1");
|
||||||
|
Services.prefs.setCharPref("identity.fxaccounts.oauth.client_id", "abc123");
|
||||||
|
|
||||||
|
|
||||||
function run_test() {
|
function run_test() {
|
||||||
run_next_test();
|
run_next_test();
|
||||||
}
|
}
|
||||||
@ -681,6 +687,46 @@ add_test(function test_sign_out_with_remote_error() {
|
|||||||
fxa.signOut();
|
fxa.signOut();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
add_test(function test_getOAuthToken() {
|
||||||
|
let fxa = new MockFxAccounts();
|
||||||
|
let alice = getTestUser("alice");
|
||||||
|
let getTokenFromAssertionCalled = false;
|
||||||
|
|
||||||
|
fxa.internal._d_signCertificate.resolve("cert1");
|
||||||
|
|
||||||
|
// create a mock oauth client
|
||||||
|
let client = new FxAccountsOAuthGrantClient({
|
||||||
|
serverURL: "http://example.com/v1",
|
||||||
|
client_id: "abc123"
|
||||||
|
});
|
||||||
|
client.getTokenFromAssertion = function () {
|
||||||
|
getTokenFromAssertionCalled = true;
|
||||||
|
return Promise.resolve({ access_token: "token" });
|
||||||
|
};
|
||||||
|
|
||||||
|
fxa.setSignedInUser(alice).then(
|
||||||
|
() => {
|
||||||
|
fxa.getOAuthToken({ scope: "profile", client: client }).then(
|
||||||
|
(result) => {
|
||||||
|
do_check_true(getTokenFromAssertionCalled);
|
||||||
|
do_check_eq(result, "token");
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
add_test(function test_getOAuthToken_missing_scope() {
|
||||||
|
let fxa = new MockFxAccounts();
|
||||||
|
|
||||||
|
do_check_throws_message(() => {
|
||||||
|
fxa.getOAuthToken();
|
||||||
|
}, "Missing 'scope' option");
|
||||||
|
run_next_test();
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* End of tests.
|
* End of tests.
|
||||||
* Utility functions follow.
|
* Utility functions follow.
|
||||||
@ -743,7 +789,7 @@ function do_check_throws(func, result, stack)
|
|||||||
if (ex.name == result) {
|
if (ex.name == result) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
do_throw("Expected result " + result + ", caught " + ex, stack);
|
do_throw("Expected result " + result + ", caught " + ex.name, stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
|
256
services/fxaccounts/tests/xpcshell/test_oauth_grant_client.js
Normal file
256
services/fxaccounts/tests/xpcshell/test_oauth_grant_client.js
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
Cu.import("resource://gre/modules/FxAccountsCommon.js");
|
||||||
|
Cu.import("resource://gre/modules/FxAccountsOAuthGrantClient.jsm");
|
||||||
|
|
||||||
|
const CLIENT_OPTIONS = {
|
||||||
|
serverURL: "http://127.0.0.1:9010/v1",
|
||||||
|
client_id: 'abc123'
|
||||||
|
};
|
||||||
|
|
||||||
|
const STATUS_SUCCESS = 200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mock request responder
|
||||||
|
* @param {String} response
|
||||||
|
* Mocked raw response from the server
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
let mockResponse = function (response) {
|
||||||
|
return function () {
|
||||||
|
return {
|
||||||
|
setHeader: function () {},
|
||||||
|
post: function () {
|
||||||
|
this.response = response;
|
||||||
|
this.onComplete();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mock request error responder
|
||||||
|
* @param {Error} error
|
||||||
|
* Error object
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
let mockResponseError = function (error) {
|
||||||
|
return function () {
|
||||||
|
return {
|
||||||
|
setHeader: function () {},
|
||||||
|
post: function () {
|
||||||
|
this.onComplete(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
add_test(function missingParams () {
|
||||||
|
let client = new FxAccountsOAuthGrantClient(CLIENT_OPTIONS);
|
||||||
|
try {
|
||||||
|
client.getTokenFromAssertion()
|
||||||
|
} catch (e) {
|
||||||
|
do_check_eq(e.message, "Missing 'assertion' parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
client.getTokenFromAssertion("assertion")
|
||||||
|
} catch (e) {
|
||||||
|
do_check_eq(e.message, "Missing 'scope' parameter");
|
||||||
|
}
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
});
|
||||||
|
|
||||||
|
add_test(function successfulResponse () {
|
||||||
|
let client = new FxAccountsOAuthGrantClient(CLIENT_OPTIONS);
|
||||||
|
let response = {
|
||||||
|
success: true,
|
||||||
|
status: STATUS_SUCCESS,
|
||||||
|
body: "{\"access_token\":\"http://example.com/image.jpeg\",\"id\":\"0d5c1a89b8c54580b8e3e8adadae864a\"}",
|
||||||
|
};
|
||||||
|
|
||||||
|
client._Request = new mockResponse(response);
|
||||||
|
client.getTokenFromAssertion("assertion", "scope")
|
||||||
|
.then(
|
||||||
|
function (result) {
|
||||||
|
do_check_eq(result.access_token, "http://example.com/image.jpeg");
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
add_test(function parseErrorResponse () {
|
||||||
|
let client = new FxAccountsOAuthGrantClient(CLIENT_OPTIONS);
|
||||||
|
let response = {
|
||||||
|
success: true,
|
||||||
|
status: STATUS_SUCCESS,
|
||||||
|
body: "unexpected",
|
||||||
|
};
|
||||||
|
|
||||||
|
client._Request = new mockResponse(response);
|
||||||
|
client.getTokenFromAssertion("assertion", "scope")
|
||||||
|
.then(
|
||||||
|
null,
|
||||||
|
function (e) {
|
||||||
|
do_check_eq(e.name, "FxAccountsOAuthGrantClientError");
|
||||||
|
do_check_eq(e.code, STATUS_SUCCESS);
|
||||||
|
do_check_eq(e.errno, ERRNO_PARSE);
|
||||||
|
do_check_eq(e.error, ERROR_PARSE);
|
||||||
|
do_check_eq(e.message, "unexpected");
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_test(function serverErrorResponse () {
|
||||||
|
let client = new FxAccountsOAuthGrantClient(CLIENT_OPTIONS);
|
||||||
|
let response = {
|
||||||
|
status: 400,
|
||||||
|
body: "{ \"code\": 400, \"errno\": 104, \"error\": \"Bad Request\", \"message\": \"Unauthorized\", \"reason\": \"Invalid fxa assertion\" }",
|
||||||
|
};
|
||||||
|
|
||||||
|
client._Request = new mockResponse(response);
|
||||||
|
client.getTokenFromAssertion("blah", "scope")
|
||||||
|
.then(
|
||||||
|
null,
|
||||||
|
function (e) {
|
||||||
|
do_check_eq(e.name, "FxAccountsOAuthGrantClientError");
|
||||||
|
do_check_eq(e.code, 400);
|
||||||
|
do_check_eq(e.errno, 104);
|
||||||
|
do_check_eq(e.error, "Bad Request");
|
||||||
|
do_check_eq(e.message, "Unauthorized");
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_test(function networkErrorResponse () {
|
||||||
|
let client = new FxAccountsOAuthGrantClient({
|
||||||
|
serverURL: "http://",
|
||||||
|
client_id: "abc123"
|
||||||
|
});
|
||||||
|
client.getTokenFromAssertion("assertion", "scope")
|
||||||
|
.then(
|
||||||
|
null,
|
||||||
|
function (e) {
|
||||||
|
do_check_eq(e.name, "FxAccountsOAuthGrantClientError");
|
||||||
|
do_check_eq(e.code, null);
|
||||||
|
do_check_eq(e.errno, ERRNO_NETWORK);
|
||||||
|
do_check_eq(e.error, ERROR_NETWORK);
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_test(function unsupportedMethod () {
|
||||||
|
let client = new FxAccountsOAuthGrantClient(CLIENT_OPTIONS);
|
||||||
|
|
||||||
|
return client._createRequest("/", "PUT")
|
||||||
|
.then(
|
||||||
|
null,
|
||||||
|
function (e) {
|
||||||
|
do_check_eq(e.name, "FxAccountsOAuthGrantClientError");
|
||||||
|
do_check_eq(e.code, ERROR_CODE_METHOD_NOT_ALLOWED);
|
||||||
|
do_check_eq(e.errno, ERRNO_NETWORK);
|
||||||
|
do_check_eq(e.error, ERROR_NETWORK);
|
||||||
|
do_check_eq(e.message, ERROR_MSG_METHOD_NOT_ALLOWED);
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_test(function onCompleteRequestError () {
|
||||||
|
let client = new FxAccountsOAuthGrantClient(CLIENT_OPTIONS);
|
||||||
|
client._Request = new mockResponseError(new Error("onComplete error"));
|
||||||
|
client.getTokenFromAssertion("assertion", "scope")
|
||||||
|
.then(
|
||||||
|
null,
|
||||||
|
function (e) {
|
||||||
|
do_check_eq(e.name, "FxAccountsOAuthGrantClientError");
|
||||||
|
do_check_eq(e.code, null);
|
||||||
|
do_check_eq(e.errno, ERRNO_NETWORK);
|
||||||
|
do_check_eq(e.error, ERROR_NETWORK);
|
||||||
|
do_check_eq(e.message, "Error: onComplete error");
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
add_test(function constructorTests() {
|
||||||
|
validationHelper(undefined,
|
||||||
|
"Error: Missing configuration options");
|
||||||
|
|
||||||
|
validationHelper({},
|
||||||
|
"Error: Missing 'serverURL' parameter");
|
||||||
|
|
||||||
|
validationHelper({ serverURL: "http://example.com" },
|
||||||
|
"Error: Missing 'client_id' parameter");
|
||||||
|
|
||||||
|
validationHelper({ client_id: "123ABC" },
|
||||||
|
"Error: Missing 'serverURL' parameter");
|
||||||
|
|
||||||
|
validationHelper({ client_id: "123ABC", serverURL: "badUrl" },
|
||||||
|
"Error: Invalid 'serverURL'");
|
||||||
|
|
||||||
|
run_next_test();
|
||||||
|
});
|
||||||
|
|
||||||
|
add_test(function errorTests() {
|
||||||
|
let error1 = new FxAccountsOAuthGrantClientError();
|
||||||
|
do_check_eq(error1.name, "FxAccountsOAuthGrantClientError");
|
||||||
|
do_check_eq(error1.code, null);
|
||||||
|
do_check_eq(error1.errno, ERRNO_UNKNOWN_ERROR);
|
||||||
|
do_check_eq(error1.error, ERROR_UNKNOWN);
|
||||||
|
do_check_eq(error1.message, null);
|
||||||
|
|
||||||
|
let error2 = new FxAccountsOAuthGrantClientError({
|
||||||
|
code: STATUS_SUCCESS,
|
||||||
|
errno: 1,
|
||||||
|
error: "Error",
|
||||||
|
message: "Something",
|
||||||
|
});
|
||||||
|
let fields2 = error2._toStringFields();
|
||||||
|
let statusCode = 1;
|
||||||
|
|
||||||
|
do_check_eq(error2.name, "FxAccountsOAuthGrantClientError");
|
||||||
|
do_check_eq(error2.code, STATUS_SUCCESS);
|
||||||
|
do_check_eq(error2.errno, statusCode);
|
||||||
|
do_check_eq(error2.error, "Error");
|
||||||
|
do_check_eq(error2.message, "Something");
|
||||||
|
|
||||||
|
do_check_eq(fields2.name, "FxAccountsOAuthGrantClientError");
|
||||||
|
do_check_eq(fields2.code, STATUS_SUCCESS);
|
||||||
|
do_check_eq(fields2.errno, statusCode);
|
||||||
|
do_check_eq(fields2.error, "Error");
|
||||||
|
do_check_eq(fields2.message, "Something");
|
||||||
|
|
||||||
|
do_check_true(error2.toString().indexOf("Something") >= 0);
|
||||||
|
run_next_test();
|
||||||
|
});
|
||||||
|
|
||||||
|
function run_test() {
|
||||||
|
run_next_test();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quick way to test the "FxAccountsOAuthGrantClient" constructor.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* FxAccountsOAuthGrantClient constructor options
|
||||||
|
* @param {String} expected
|
||||||
|
* Expected error message
|
||||||
|
* @returns {*}
|
||||||
|
*/
|
||||||
|
function validationHelper(options, expected) {
|
||||||
|
try {
|
||||||
|
new FxAccountsOAuthGrantClient(options);
|
||||||
|
} catch (e) {
|
||||||
|
return do_check_eq(e.toString(), expected);
|
||||||
|
}
|
||||||
|
throw new Error("Validation helper error");
|
||||||
|
}
|
@ -13,4 +13,5 @@ skip-if = appname == 'b2g' # login manager storage only used on desktop.
|
|||||||
skip-if = appname != 'b2g'
|
skip-if = appname != 'b2g'
|
||||||
reason = FxAccountsManager is only available for B2G for now
|
reason = FxAccountsManager is only available for B2G for now
|
||||||
[test_oauth_client.js]
|
[test_oauth_client.js]
|
||||||
|
[test_oauth_grant_client.js]
|
||||||
[test_profile_client.js]
|
[test_profile_client.js]
|
||||||
|
Loading…
Reference in New Issue
Block a user