UNPKG

voluptasmollitia

Version:
1,491 lines (1,357 loc) 122 kB
/** * @license * Copyright 2017 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /** * @fileoverview Tests for authcredential.js */ goog.provide('fireauth.AuthCredentialTest'); goog.require('fireauth.Auth'); goog.require('fireauth.AuthCredential'); goog.require('fireauth.AuthError'); goog.require('fireauth.AuthProvider'); goog.require('fireauth.EmailAuthCredential'); goog.require('fireauth.EmailAuthProvider'); goog.require('fireauth.FacebookAuthProvider'); goog.require('fireauth.GithubAuthProvider'); goog.require('fireauth.GoogleAuthProvider'); goog.require('fireauth.IdToken'); goog.require('fireauth.MultiFactorSession'); goog.require('fireauth.OAuthCredential'); goog.require('fireauth.OAuthProvider'); goog.require('fireauth.PhoneAuthCredential'); goog.require('fireauth.PhoneAuthProvider'); goog.require('fireauth.PhoneMultiFactorInfo'); goog.require('fireauth.RpcHandler'); goog.require('fireauth.SAMLAuthCredential'); goog.require('fireauth.SAMLAuthProvider'); goog.require('fireauth.TwitterAuthProvider'); goog.require('fireauth.authenum.Error'); goog.require('fireauth.common.testHelper'); goog.require('fireauth.deprecation'); goog.require('fireauth.idp.ProviderId'); goog.require('fireauth.idp.SignInMethod'); goog.require('fireauth.util'); goog.require('goog.Promise'); goog.require('goog.testing.MockControl'); goog.require('goog.testing.PropertyReplacer'); goog.require('goog.testing.jsunit'); goog.require('goog.testing.recordFunction'); goog.setTestOnly('fireauth.AuthCredentialTest'); var mockControl; var stubs = new goog.testing.PropertyReplacer(); var rpcHandler = new fireauth.RpcHandler('apiKey'); var responseForIdToken; var app = firebase.initializeApp({ apiKey: 'myApiKey' }); var auth = new fireauth.Auth(app); var jwt = fireauth.common.testHelper.createMockJwt({ 'firebase': { 'sign_in_provider': 'password' } }); var factorDisplayName = 'Work phone number'; var pendingCredential = 'MFA_PENDING_CREDENTIAL'; var successTokenResponse = { 'idToken': fireauth.common.testHelper.createMockJwt({ 'firebase': { 'sign_in_provider': 'password', 'sign_in_second_factor': 'phone' } }), 'refreshToken': 'REFRESH_TOKEN' }; var now = new Date(); function setUp() { responseForIdToken = { 'idToken': 'ID_TOKEN' }; stubs.replace( fireauth.util, 'getCurrentUrl', function() { // Simulates a non http://localhost current URL. return 'http://www.example.com'; }); stubs.replace( fireauth.RpcHandler.prototype, 'verifyAssertion', goog.testing.recordFunction(function(request) { return goog.Promise.resolve(responseForIdToken); })); stubs.replace( fireauth.RpcHandler.prototype, 'verifyPassword', goog.testing.recordFunction(function(request) { return goog.Promise.resolve(responseForIdToken); })); stubs.replace( fireauth.RpcHandler.prototype, 'emailLinkSignIn', goog.testing.recordFunction(function(request) { return goog.Promise.resolve(responseForIdToken); })); stubs.replace( fireauth.RpcHandler.prototype, 'emailLinkSignInForLinking', goog.testing.recordFunction(function(request) { return goog.Promise.resolve(responseForIdToken); })); stubs.replace( fireauth.RpcHandler.prototype, 'verifyAssertionForLinking', goog.testing.recordFunction(function(request) { return goog.Promise.resolve(responseForIdToken); })); stubs.replace( fireauth.RpcHandler.prototype, 'verifyAssertionForExisting', goog.testing.recordFunction(function(request) { return goog.Promise.resolve(responseForIdToken); })); stubs.replace( fireauth.RpcHandler.prototype, 'updateEmailAndPassword', goog.testing.recordFunction(goog.Promise.resolve)); // Internally we should not be using any deprecated methods. stubs.replace(fireauth.deprecation, 'log', function(message) { fail('Deprecation message unexpectedly displayed: ' + message); }); mockControl = new goog.testing.MockControl(); } function tearDown() { mockControl.$verifyAll(); mockControl.$tearDown(); stubs.reset(); } /** * Initialize the IdToken mocks for parsing an expected ID token and returning * the expected UID string. * @param {?string|undefined} expectedIdToken The expected ID token string. * @param {string} expectedUid The expected UID to be returned if the token is * valid. */ function initializeIdTokenMocks(expectedIdToken, expectedUid) { // Mock idToken parsing. var tokenInstance = mockControl.createStrictMock(fireauth.IdToken); var idTokenParse = mockControl.createMethodMock(fireauth.IdToken, 'parse'); if (!!expectedIdToken) { // Valid expected ID token string. idTokenParse(expectedIdToken).$returns(tokenInstance).$once(); // Return expected token UID when getLocalId() called. tokenInstance.getLocalId().$returns(expectedUid); } else { // No ID token string provided. idTokenParse(expectedIdToken).$returns(null).$once(); } mockControl.$replayAll(); } /** * Assert that the correct request is sent to RPC handler * verifyAssertionFor. * @param {?Object} request The verifyAssertion request. */ function assertRpcHandlerVerifyAssertion(request) { assertEquals( 1, fireauth.RpcHandler.prototype.verifyAssertion.getCallCount()); assertObjectEquals( request, fireauth.RpcHandler.prototype.verifyAssertion .getLastCall() .getArgument(0)); } /** * Asserts that the correct request is sent to RPC handler verifyPassword. * @param {string} email The email in verifyPassword request. * @param {string} password The password in verifyPassword request. */ function assertRpcHandlerVerifyPassword(email, password) { assertEquals( 1, fireauth.RpcHandler.prototype.verifyPassword.getCallCount()); assertObjectEquals( email, fireauth.RpcHandler.prototype.verifyPassword .getLastCall() .getArgument(0)); assertObjectEquals( password, fireauth.RpcHandler.prototype.verifyPassword .getLastCall() .getArgument(1)); } /** * Asserts that the correct request is sent to RPC handler emailLinkSignIn. * @param {string} email The email in emailLinkSignIn request. * @param {string} oobCode The oobCode in emailLinkSignIn request. */ function assertRpcHandlerEmailLinkSignIn(email, oobCode) { assertEquals(1, fireauth.RpcHandler.prototype.emailLinkSignIn.getCallCount()); assertObjectEquals( email, fireauth.RpcHandler.prototype.emailLinkSignIn.getLastCall().getArgument( 0)); assertObjectEquals( oobCode, fireauth.RpcHandler.prototype.emailLinkSignIn.getLastCall().getArgument( 1)); } /** * Asserts that the correct request is sent to RPC handler * emailLinkSignInForLinking. * @param {string} idToken The idToken in emailLinkSignInForLinking request. * @param {string} email The email in emailLinkSignInForLinking request. * @param {string} oobCode The oobCode in emailLinkSignInForLinking request. */ function assertRpcHandlerEmailLinkSignInForLinking(idToken, email, oobCode) { assertEquals(1, fireauth.RpcHandler.prototype.emailLinkSignInForLinking .getCallCount()); assertObjectEquals( idToken, fireauth.RpcHandler.prototype.emailLinkSignInForLinking .getLastCall().getArgument(0)); assertObjectEquals( email, fireauth.RpcHandler.prototype.emailLinkSignInForLinking .getLastCall().getArgument(1)); assertObjectEquals( oobCode, fireauth.RpcHandler.prototype.emailLinkSignInForLinking .getLastCall().getArgument(2)); } /** * Assert that the correct request is sent to RPC handler * verifyAssertionForLinking. * @param {?Object} request The verifyAssertionForLinking request. */ function assertRpcHandlerVerifyAssertionForLinking(request) { assertEquals( 1, fireauth.RpcHandler.prototype.verifyAssertionForLinking.getCallCount()); assertObjectEquals( request, fireauth.RpcHandler.prototype.verifyAssertionForLinking .getLastCall() .getArgument(0)); } /** * Assert that the correct request is sent to RPC handler * verifyAssertionForExisting. * @param {?Object} request The verifyAssertionForLinking request. */ function assertRpcHandlerVerifyAssertionForExisting(request) { assertEquals( 1, fireauth.RpcHandler.prototype.verifyAssertionForExisting.getCallCount()); assertObjectEquals( request, fireauth.RpcHandler.prototype.verifyAssertionForExisting .getLastCall() .getArgument(0)); } /** * Assert that the correct request is sent to RPC handler * updateEmailAndPassword. * @param {!string} idToken The ID token in updateEmailAndPassword request. * @param {!string} email The email in updateEmailAndPassword request. * @param {!string} password The password in updateEmailAndPassword request. */ function assertRpcHandlerUpdateEmailAndPassword(idToken, email, password) { assertEquals( 1, fireauth.RpcHandler.prototype.updateEmailAndPassword.getCallCount()); assertObjectEquals( idToken, fireauth.RpcHandler.prototype.updateEmailAndPassword .getLastCall() .getArgument(0)); assertObjectEquals( email, fireauth.RpcHandler.prototype.updateEmailAndPassword .getLastCall() .getArgument(1)); assertObjectEquals( password, fireauth.RpcHandler.prototype.updateEmailAndPassword .getLastCall() .getArgument(2)); } /** * Test invalid Auth credential. */ function testInvalidCredential() { var errorOAuth1 = new fireauth.AuthError( fireauth.authenum.Error.ARGUMENT_ERROR, 'credential failed: expected 2 arguments ' + '(the OAuth access token and secret).'); var errorOAuth2 = new fireauth.AuthError( fireauth.authenum.Error.ARGUMENT_ERROR, 'credential failed: expected 1 argument ' + '(the OAuth access token).'); var errorOidc = new fireauth.AuthError( fireauth.authenum.Error.ARGUMENT_ERROR, 'credential failed: must provide the ID token and/or the access ' + 'token.'); try { fireauth.FacebookAuthProvider.credential(''); fail('Should have triggered an invalid Auth credential error!'); } catch (e) { fireauth.common.testHelper.assertErrorEquals(errorOAuth2, e); } try { fireauth.GithubAuthProvider.credential(''); fail('Should have triggered an invalid Auth credential error!'); } catch (e) { fireauth.common.testHelper.assertErrorEquals(errorOAuth2, e); } try { fireauth.GoogleAuthProvider.credential('', ''); fail('Should have triggered an invalid Auth credential error!'); } catch (e) { fireauth.common.testHelper.assertErrorEquals(errorOidc, e); } try { fireauth.TwitterAuthProvider.credential('twitterAccessToken', ''); fail('Should have triggered an invalid Auth credential error!'); } catch (e) { fireauth.common.testHelper.assertErrorEquals(errorOAuth1, e); } try { new fireauth.OAuthProvider('example.com').credential('', ''); fail('Should have triggered an invalid Auth credential error!'); } catch (e) { fireauth.common.testHelper.assertErrorEquals(errorOidc, e); } // Test invalid credentials from response. // Empty response. assertNull(fireauth.AuthProvider.getCredentialFromResponse({})); // Missing OAuth response. assertNull( fireauth.AuthProvider.getCredentialFromResponse({ 'providerId': 'facebook.com' })); } function testOAuthCredential() { var provider = new fireauth.OAuthProvider('example.com'); var authCredential = provider.credential({ 'idToken': 'exampleIdToken', 'accessToken': 'exampleAccessToken' }); assertEquals('exampleIdToken', authCredential['idToken']); assertEquals('exampleAccessToken', authCredential['accessToken']); assertEquals('example.com', authCredential['providerId']); assertEquals('example.com', authCredential['signInMethod']); authCredential.getIdTokenProvider(rpcHandler); assertObjectEquals( { 'oauthAccessToken': 'exampleAccessToken', 'oauthIdToken': 'exampleIdToken', 'providerId': 'example.com', 'signInMethod': 'example.com' }, authCredential.toPlainObject()); assertRpcHandlerVerifyAssertion({ // requestUri should be http://localhost regardless of current URL. 'requestUri': 'http://localhost', 'postBody': 'id_token=exampleIdToken&access_token=exampleAccessToken' + '&providerId=example.com' }); // Test toJSON and fromJSON for current OAuthCredential. assertObjectEquals( authCredential, fireauth.OAuthCredential.fromJSON(authCredential.toPlainObject())); assertObjectEquals( authCredential, fireauth.AuthCredential.fromPlainObject(authCredential.toPlainObject())); assertObjectEquals( authCredential, fireauth.AuthCredential.fromPlainObject( JSON.stringify(authCredential.toPlainObject()))); } function testOAuthCredential_oldAPI() { var provider = new fireauth.OAuthProvider('example.com'); // Initialize the OAuth credential using the old API. var authCredential = provider.credential( 'exampleIdToken', 'exampleAccessToken'); assertEquals('exampleIdToken', authCredential['idToken']); assertEquals('exampleAccessToken', authCredential['accessToken']); assertEquals('example.com', authCredential['providerId']); assertEquals('example.com', authCredential['signInMethod']); authCredential.getIdTokenProvider(rpcHandler); assertObjectEquals( { 'oauthAccessToken': 'exampleAccessToken', 'oauthIdToken': 'exampleIdToken', 'providerId': 'example.com', 'signInMethod': 'example.com' }, authCredential.toPlainObject()); assertRpcHandlerVerifyAssertion({ // requestUri should be http://localhost regardless of current URL. 'requestUri': 'http://localhost', 'postBody': 'id_token=exampleIdToken&access_token=exampleAccessToken' + '&providerId=example.com' }); // Test toJSON and fromJSON for current OAuthCredential. assertObjectEquals( authCredential, fireauth.OAuthCredential.fromJSON(authCredential.toPlainObject())); assertObjectEquals( authCredential, fireauth.AuthCredential.fromPlainObject(authCredential.toPlainObject())); } function testOAuthCredential_idTokenNonce() { // Test using an OIDC ID token/nonce credential. var provider = new fireauth.OAuthProvider('oidc.provider'); var authCredential = provider.credential({ 'idToken': 'OIDC_ID_TOKEN', 'rawNonce': 'NONCE' }); assertEquals('OIDC_ID_TOKEN', authCredential['idToken']); assertEquals('NONCE', authCredential['nonce']); assertUndefined(authCredential['accessToken']); assertEquals('oidc.provider', authCredential['providerId']); assertEquals('oidc.provider', authCredential['signInMethod']); authCredential.getIdTokenProvider(rpcHandler); assertObjectEquals( { 'oauthIdToken': 'OIDC_ID_TOKEN', 'nonce': 'NONCE', 'providerId': 'oidc.provider', 'signInMethod': 'oidc.provider' }, authCredential.toPlainObject()); // Confirm expected verifyAssertion request sent. nonce is passed in postBody. assertRpcHandlerVerifyAssertion({ 'requestUri': 'http://localhost', 'postBody': 'id_token=OIDC_ID_TOKEN&providerId=oidc.provider&nonce=NONCE' }); // Test toJSON and fromJSON for current OAuthCredential. assertObjectEquals( authCredential, fireauth.OAuthCredential.fromJSON(authCredential.toPlainObject())); assertObjectEquals( authCredential, fireauth.AuthCredential.fromPlainObject(authCredential.toPlainObject())); } function testOAuthCredential_pendingToken() { // Test using an OIDC ID token/pending token credential. var authCredential = new fireauth.OAuthCredential( 'oidc.provider', { 'pendingToken': 'PENDING_TOKEN', // Nonce should be ignored. 'nonce': 'NONCE', 'idToken': 'OIDC_ID_TOKEN' }, 'oidc.provider'); assertEquals('OIDC_ID_TOKEN', authCredential['idToken']); assertUndefined('NONCE', authCredential['nonce']); assertUndefined(authCredential['accessToken']); assertEquals('oidc.provider', authCredential['providerId']); assertEquals('oidc.provider', authCredential['signInMethod']); authCredential.getIdTokenProvider(rpcHandler); assertObjectEquals( { 'oauthIdToken': 'OIDC_ID_TOKEN', 'pendingToken': 'PENDING_TOKEN', 'providerId': 'oidc.provider', 'signInMethod': 'oidc.provider' }, authCredential.toPlainObject()); // Confirm only pending token passed in request. assertRpcHandlerVerifyAssertion({ 'requestUri': 'http://localhost', 'pendingToken': 'PENDING_TOKEN' }); // Test toJSON and fromJSON for current OAuthCredential. assertObjectEquals( authCredential, fireauth.OAuthCredential.fromJSON(authCredential.toPlainObject())); assertObjectEquals( authCredential, fireauth.AuthCredential.fromPlainObject(authCredential.toPlainObject())); } function testInvalidOAuthCredential() { // Test the case where invalid arguments were passed to the OAuthCredential // constructor. The constructor is only called internally, so the errors are // internal errors. try { new fireauth.OAuthCredential('twitter.com', { 'oauthToken': 'token' // OAuth1 secret missing. }); fail('Should have triggered an invalid Auth credential error!'); } catch (e) { assertEquals('auth/internal-error', e.code); } } function testOAuthProvider_constructor() { var provider = new fireauth.OAuthProvider('example.com'); assertTrue(provider['isOAuthProvider']); assertEquals('example.com', provider['providerId']); // Should not throw an error. assertNotThrows(function() { fireauth.AuthProvider.checkIfOAuthSupported(provider); }); } function testOAuthProvider_scopes() { var provider = new fireauth.OAuthProvider('example.com'); provider.addScope('scope1'); assertArrayEquals(['scope1'], provider.getScopes()); provider.addScope('scope2').addScope('scope3'); assertArrayEquals(['scope1', 'scope2', 'scope3'], provider.getScopes()); } function testOAuthProvider_customParameters() { var provider = new fireauth.OAuthProvider('example.com'); // Set OAuth custom parameters. provider.setCustomParameters({ // Valid OAuth2/OIDC parameters. 'login_hint': 'user@example.com', 'prompt': 'consent', 'include_granted_scopes': true, // Reserved parameters below should be filtered out. 'client_id': 'CLIENT_ID', 'response_type': 'token', 'scope': 'scope1', 'redirect_uri': 'https://www.evil.com', 'state': 'STATE' }); // Get custom parameters should only return the valid parameters. assertObjectEquals({ 'login_hint': 'user@example.com', 'prompt': 'consent', 'include_granted_scopes': 'true', }, provider.getCustomParameters()); // Modify custom parameters. provider.setCustomParameters({ 'login_hint': 'user2@example.com' }).setCustomParameters({ 'login_hint': 'user3@example.com' }); // Parameters should be updated. assertObjectEquals({ 'login_hint': 'user3@example.com' }, provider.getCustomParameters()); } function testOAuthProvider_chainedMethods() { // Test that method chaining works. var provider = new fireauth.OAuthProvider('example.com') .addScope('scope1') .addScope('scope2') .setCustomParameters({ 'login_hint': 'user@example.com' }) .addScope('scope3'); assertArrayEquals(['scope1', 'scope2', 'scope3'], provider.getScopes()); assertObjectEquals({ 'login_hint': 'user@example.com' }, provider.getCustomParameters()); } function testOAuthProvider_getCredentialFromResponse() { var provider = new fireauth.OAuthProvider('example.com'); var authCredential = provider.credential({ 'idToken': 'exampleIdToken', 'accessToken': 'exampleAccessToken' }); assertObjectEquals( authCredential.toPlainObject(), fireauth.AuthProvider.getCredentialFromResponse({ 'oauthAccessToken': 'exampleAccessToken', 'oauthIdToken': 'exampleIdToken', 'providerId': 'example.com', 'signInMethod': 'example.com' }).toPlainObject()); } function testOAuthProvider_getCredentialFromResponse_accessTokenOnly() { // Test Auth credential from response with access token only. var provider = new fireauth.OAuthProvider('example.com'); var authCredential = provider.credential({ 'accessToken': 'exampleAccessToken' }); assertObjectEquals( authCredential.toPlainObject(), fireauth.AuthProvider.getCredentialFromResponse({ 'oauthAccessToken': 'exampleAccessToken', 'providerId': 'example.com', 'signInMethod': 'example.com' }).toPlainObject()); } function testOAuthProvider_getCredentialFromResponse_idTokenOnly() { // Test Auth credential from response with ID token only. var provider = new fireauth.OAuthProvider('example.com'); var authCredential = provider.credential({ 'idToken': 'exampleIdToken' }); assertObjectEquals( authCredential.toPlainObject(), fireauth.AuthProvider.getCredentialFromResponse({ 'oauthIdToken': 'exampleIdToken', 'providerId': 'example.com', 'signInMethod': 'example.com' }).toPlainObject()); } function testOAuthProvider_getCredentialFromResponse_idTokenAndNonce() { // Test Auth credential from response with ID token/nonce. var provider = new fireauth.OAuthProvider('example.com'); var authCredential = provider.credential({ 'idToken': 'exampleIdToken', 'rawNonce': 'NONCE' }); assertObjectEquals( authCredential.toPlainObject(), fireauth.AuthProvider.getCredentialFromResponse({ 'oauthIdToken': 'exampleIdToken', 'providerId': 'example.com', // This will be injected in rpcHandler. 'nonce': 'NONCE' }).toPlainObject()); } function testOAuthProvider_getCredentialFromResponse_pendingTokenIdToken() { // Test Auth credential from response with ID token/pending token. var authCredential = new fireauth.OAuthCredential( 'oidc.provider', { 'pendingToken': 'PENDING_TOKEN', 'idToken': 'OIDC_ID_TOKEN' }, 'oidc.provider'); assertObjectEquals( authCredential.toPlainObject(), fireauth.AuthProvider.getCredentialFromResponse({ 'oauthIdToken': 'OIDC_ID_TOKEN', 'pendingToken': 'PENDING_TOKEN', 'providerId': 'oidc.provider' }).toPlainObject()); } function testOAuthProvider_getCredentialFromResponse_pendingTokenAccessToken() { // Test Auth credential from response with access token/pending token. var authCredential = new fireauth.OAuthCredential( 'oidc.provider', { 'pendingToken': 'PENDING_TOKEN', 'accessToken': 'ACCESS_TOKEN' }, 'oidc.provider'); assertObjectEquals( authCredential.toPlainObject(), fireauth.AuthProvider.getCredentialFromResponse({ 'oauthAccessToken': 'ACCESS_TOKEN', 'pendingToken': 'PENDING_TOKEN', 'providerId': 'oidc.provider' }).toPlainObject()); } function testOAuthProvider_getCredentialFromResponse_pendingTokenAndNonce() { // Test nonce ignored for pending token. var authCredential = new fireauth.OAuthCredential( 'oidc.provider', { 'pendingToken': 'PENDING_TOKEN', 'idToken': 'OIDC_ID_TOKEN' }, 'oidc.provider'); assertObjectEquals( authCredential.toPlainObject(), fireauth.AuthProvider.getCredentialFromResponse({ 'oauthIdToken': 'OIDC_ID_TOKEN', 'pendingToken': 'PENDING_TOKEN', 'providerId': 'oidc.provider', // This shouldn't be injected but if it did, it will be ignored in // favor of pending token. 'nonce': 'NONCE' }).toPlainObject()); } function testOAuthCredential_linkToIdToken() { var provider = new fireauth.OAuthProvider('example.com'); var authCredential = provider.credential({ 'idToken': 'exampleIdToken', 'accessToken': 'exampleAccessToken' }); authCredential.linkToIdToken(rpcHandler, 'myIdToken'); assertRpcHandlerVerifyAssertionForLinking({ // requestUri should be http://localhost regardless of current URL. 'requestUri': 'http://localhost', 'postBody': 'id_token=exampleIdToken&access_token=exampleAccessToken' + '&providerId=example.com', 'idToken': 'myIdToken' }); } function testOAuthCredential_matchIdTokenWithUid() { // Mock idToken parsing. initializeIdTokenMocks('ID_TOKEN', '1234'); var provider = new fireauth.OAuthProvider('example.com'); var authCredential = provider.credential({ 'idToken': 'exampleIdToken', 'accessToken': 'exampleAccessToken' }); var p = authCredential.matchIdTokenWithUid(rpcHandler, '1234'); assertRpcHandlerVerifyAssertionForExisting({ // requestUri should be http://localhost regardless of current URL. 'requestUri': 'http://localhost', 'postBody': 'id_token=exampleIdToken&access_token=exampleAccessToken' + '&providerId=example.com' }); return p; } function testOAuthCredential_withNonce_linkToIdToken() { var provider = new fireauth.OAuthProvider('oidc.provider'); var authCredential = provider.credential({ 'idToken': 'exampleIdToken', 'rawNonce': 'NONCE' }); var p = authCredential.linkToIdToken(rpcHandler, 'myIdToken'); // Confirm expected verifyAssertion request for linking flow using ID // token/nonce. assertRpcHandlerVerifyAssertionForLinking({ 'requestUri': 'http://localhost', // nonce is appended to postBody. 'postBody': 'id_token=exampleIdToken&providerId=oidc.provider' + '&nonce=NONCE', 'idToken': 'myIdToken' }); return p; } function testOAuthCredential_withNonce_matchIdTokenWithUid() { // Mock idToken parsing. initializeIdTokenMocks('ID_TOKEN', '1234'); var provider = new fireauth.OAuthProvider('oidc.provider'); var authCredential = provider.credential({ 'idToken': 'exampleIdToken', 'rawNonce': 'NONCE' }); var p = authCredential.matchIdTokenWithUid(rpcHandler, '1234'); // Confirm expected verifyAssertion request for matchIdToken flow using ID // token/nonce. assertRpcHandlerVerifyAssertionForExisting({ 'requestUri': 'http://localhost', // nonce is appended to postBody. 'postBody': 'id_token=exampleIdToken&providerId=oidc.provider' + '&nonce=NONCE', }); return p; } function testOAuthCredential_withPendingToken_linkToIdToken() { var authCredential = new fireauth.OAuthCredential( 'oidc.provider', { 'pendingToken': 'PENDING_TOKEN', 'idToken': 'OIDC_ID_TOKEN' }, 'oidc.provider'); var p = authCredential.linkToIdToken(rpcHandler, 'myIdToken'); // Confirm expected verifyAssertion request for linking flow using pending // token. assertRpcHandlerVerifyAssertionForLinking({ 'requestUri': 'http://localhost', 'pendingToken': 'PENDING_TOKEN', 'idToken': 'myIdToken' }); return p; } function testOAuthCredential_withPendingToken_matchIdTokenWithUid() { // Mock idToken parsing. initializeIdTokenMocks('ID_TOKEN', '1234'); var authCredential = new fireauth.OAuthCredential( 'oidc.provider', { 'pendingToken': 'PENDING_TOKEN', 'idToken': 'OIDC_ID_TOKEN' }, 'oidc.provider'); var p = authCredential.matchIdTokenWithUid(rpcHandler, '1234'); // Confirm expected verifyAssertion request for match ID token flow using // pending token. assertRpcHandlerVerifyAssertionForExisting({ 'requestUri': 'http://localhost', 'pendingToken': 'PENDING_TOKEN' }); return p; } function testSAMLAuthCredential() { var authCredential = new fireauth.SAMLAuthCredential( 'saml.provider', 'PENDING_TOKEN'); assertEquals('saml.provider', authCredential['providerId']); assertEquals('saml.provider', authCredential['signInMethod']); authCredential.getIdTokenProvider(rpcHandler); assertObjectEquals( { 'pendingToken': 'PENDING_TOKEN', 'providerId': 'saml.provider', 'signInMethod': 'saml.provider' }, authCredential.toPlainObject()); assertRpcHandlerVerifyAssertion({ 'requestUri': 'http://localhost', 'pendingToken': 'PENDING_TOKEN' }); // Test toJSON and fromJSON for current SAMLAuthCredential. assertObjectEquals( authCredential, fireauth.SAMLAuthCredential.fromJSON(authCredential.toPlainObject())); assertObjectEquals( authCredential, fireauth.AuthCredential.fromPlainObject(authCredential.toPlainObject())); assertObjectEquals( authCredential, fireauth.AuthCredential.fromPlainObject( JSON.stringify(authCredential.toPlainObject()))); } function testSAMLAuthCredential_linkToIdToken() { var authCredential = new fireauth.SAMLAuthCredential( 'saml.provider', 'PENDING_TOKEN'); var p = authCredential.linkToIdToken(rpcHandler, 'myIdToken'); // Confirm expected verifyAssertion request for linking flow using pending // token. assertRpcHandlerVerifyAssertionForLinking({ 'requestUri': 'http://localhost', 'pendingToken': 'PENDING_TOKEN', 'idToken': 'myIdToken' }); return p; } function testSAMLAuthCredential_matchIdTokenWithUid() { // Mock idToken parsing. initializeIdTokenMocks('ID_TOKEN', '1234'); var authCredential = new fireauth.SAMLAuthCredential( 'saml.provider', 'PENDING_TOKEN'); var p = authCredential.matchIdTokenWithUid(rpcHandler, '1234'); // Confirm expected verifyAssertion request for match ID token flow using // pending token. assertRpcHandlerVerifyAssertionForExisting({ 'requestUri': 'http://localhost', 'pendingToken': 'PENDING_TOKEN' }); return p; } function testSAMLAuthProvider_constructor() { var provider = new fireauth.SAMLAuthProvider('saml.provider'); assertTrue(provider['isOAuthProvider']); assertEquals('saml.provider', provider['providerId']); // Should not throw an error. assertNotThrows(function() { fireauth.AuthProvider.checkIfOAuthSupported(provider); }); // This is unused as of now and no reserved parameters used. var expectedParameters = { // Valid Facebook OAuth 2.0 parameters. 'display': 'popup', 'auth_type': 'rerequest', 'locale': 'pt_BR', // Reserved parameters below should be filtered out. 'client_id': 'CLIENT_ID', 'response_type': 'token', 'scope': 'scope1', 'redirect_uri': 'https://www.evil.com', 'state': 'STATE' }; provider.setCustomParameters(expectedParameters); assertObjectEquals(expectedParameters, provider.getCustomParameters()); assertNull(fireauth.AuthProvider.getCredentialFromResponse({ 'providerId': 'saml.provider' })); } function testSAMLAuthCredential_getCredentialFromResponse() { // Confirm expected SAML Auth credential constructed with SAML pending token. var authCredential = new fireauth.SAMLAuthCredential( 'saml.provider', 'PENDING_TOKEN'); assertObjectEquals( authCredential.toPlainObject(), fireauth.AuthProvider.getCredentialFromResponse({ 'pendingToken': 'PENDING_TOKEN', 'providerId': 'saml.provider' }).toPlainObject()); } function testSAMLAuthProvider_invalid() { // SAML provider initialized with an invalid provider ID. assertThrows(function() { new fireauth.SAMLAuthProvider('provider.com'); }); } /** * Test Facebook Auth credential. */ function testFacebookAuthCredential() { assertEquals( fireauth.idp.ProviderId.FACEBOOK, fireauth.FacebookAuthProvider['PROVIDER_ID']); assertEquals( fireauth.idp.SignInMethod.FACEBOOK, fireauth.FacebookAuthProvider['FACEBOOK_SIGN_IN_METHOD']); var authCredential = fireauth.FacebookAuthProvider.credential( 'facebookAccessToken'); assertEquals('facebookAccessToken', authCredential['accessToken']); assertEquals(fireauth.idp.ProviderId.FACEBOOK, authCredential['providerId']); assertEquals( fireauth.idp.SignInMethod.FACEBOOK, authCredential['signInMethod']); authCredential.getIdTokenProvider(rpcHandler); assertObjectEquals( { 'oauthAccessToken': 'facebookAccessToken', 'providerId': fireauth.idp.ProviderId.FACEBOOK, 'signInMethod': fireauth.idp.SignInMethod.FACEBOOK }, authCredential.toPlainObject()); // Test toJSON and fromJSON for current Facebook OAuthCredential. assertObjectEquals( authCredential, fireauth.OAuthCredential.fromJSON(authCredential.toPlainObject())); assertObjectEquals( authCredential, fireauth.AuthCredential.fromPlainObject(authCredential.toPlainObject())); assertObjectEquals( authCredential, fireauth.AuthCredential.fromPlainObject( JSON.stringify(authCredential.toPlainObject()))); assertRpcHandlerVerifyAssertion({ // requestUri should be http://localhost regardless of current URL. 'requestUri': 'http://localhost', 'postBody': 'access_token=facebookAccessToken&providerId=' + fireauth.idp.ProviderId.FACEBOOK }); var provider = new fireauth.FacebookAuthProvider(); // Should not throw an error. assertNotThrows(function() { fireauth.AuthProvider.checkIfOAuthSupported(provider); }); assertArrayEquals([], provider.getScopes()); provider.addScope('scope1'); assertArrayEquals(['scope1'], provider.getScopes()); provider.addScope('scope2').addScope('scope3'); // Add duplicate scope. provider.addScope('scope1'); assertArrayEquals(['scope1', 'scope2', 'scope3'], provider.getScopes()); assertEquals(fireauth.idp.ProviderId.FACEBOOK, provider['providerId']); assertTrue(provider['isOAuthProvider']); // Set OAuth custom parameters. provider.setCustomParameters({ // Valid Facebook OAuth 2.0 parameters. 'display': 'popup', 'auth_type': 'rerequest', 'locale': 'pt_BR', // Reserved parameters below should be filtered out. 'client_id': 'CLIENT_ID', 'response_type': 'token', 'scope': 'scope1', 'redirect_uri': 'https://www.evil.com', 'state': 'STATE' }); // Get custom parameters should only return the valid parameters. assertObjectEquals({ 'display': 'popup', 'auth_type': 'rerequest', 'locale': 'pt_BR' }, provider.getCustomParameters()); // Modify custom parameters. provider.setCustomParameters({ // Valid Facebook OAuth 2.0 parameters. 'auth_type': 'rerequest' }); // Parameters should be updated. assertObjectEquals({ 'auth_type': 'rerequest' }, provider.getCustomParameters()); // Test Auth credential from response. assertObjectEquals( authCredential.toPlainObject(), fireauth.AuthProvider.getCredentialFromResponse({ 'providerId': 'facebook.com', 'oauthAccessToken': 'facebookAccessToken' }).toPlainObject()); } function testFacebookAuthProvider_localization() { var provider = new fireauth.FacebookAuthProvider(); // Set default language on provider. provider.setDefaultLanguage('fr_FR'); // Default language should be set as custom param. assertObjectEquals({ 'locale': 'fr_FR' }, provider.getCustomParameters()); // Set some other parameters without the provider's language. provider.setCustomParameters({ 'display': 'popup', 'client_id': 'CLIENT_ID', 'lang': 'de', 'hl': 'de' }); // The expected parameters include the provider's default language. assertObjectEquals({ 'display': 'popup', 'lang': 'de', 'hl': 'de', 'locale': 'fr_FR' }, provider.getCustomParameters()); // Set custom parameters with the provider's language. provider.setCustomParameters({ 'locale': 'pt_BR', }); // Default language should be overwritten. assertObjectEquals({ 'locale': 'pt_BR' }, provider.getCustomParameters()); // Even after setting the default language, the non-default should still // apply. provider.setDefaultLanguage('fr_FR'); assertObjectEquals({ 'locale': 'pt_BR' }, provider.getCustomParameters()); // Update custom parameters to not include a language field. provider.setCustomParameters({}); // Default should apply again. assertObjectEquals({ 'locale': 'fr_FR' }, provider.getCustomParameters()); // Set default language to null. provider.setDefaultLanguage(null); // No language should be returned anymore. assertObjectEquals({}, provider.getCustomParameters()); } function testFacebookAuthCredential_alternateConstructor() { var authCredential = fireauth.FacebookAuthProvider.credential( {'accessToken': 'facebookAccessToken'}); assertEquals('facebookAccessToken', authCredential['accessToken']); assertEquals(fireauth.idp.ProviderId.FACEBOOK, authCredential['providerId']); assertEquals( fireauth.idp.SignInMethod.FACEBOOK, authCredential['signInMethod']); assertObjectEquals( { 'oauthAccessToken': 'facebookAccessToken', 'providerId': fireauth.idp.ProviderId.FACEBOOK, 'signInMethod': fireauth.idp.SignInMethod.FACEBOOK }, authCredential.toPlainObject()); // Missing token. var expectedError = new fireauth.AuthError( fireauth.authenum.Error.ARGUMENT_ERROR); var error = assertThrows(function() { fireauth.FacebookAuthProvider.credential({}); }); assertEquals(expectedError.code, error.code); } function testFacebookAuthProvider_chainedMethods() { // Test that method chaining works. var provider = new fireauth.FacebookAuthProvider() .addScope('scope1') .addScope('scope2') .setCustomParameters({ 'locale': 'pt_BR' }) .addScope('scope3'); assertArrayEquals(['scope1', 'scope2', 'scope3'], provider.getScopes()); assertObjectEquals({ 'locale': 'pt_BR' }, provider.getCustomParameters()); } /** * Test Facebook Auth credential with non HTTP request. */ function testFacebookAuthCredential_nonHttp() { // Non http or https environment. stubs.replace( fireauth.util, 'getCurrentUrl', function() {return 'chrome-extension://SOME_LONG_ID';}); stubs.replace( fireauth.util, 'getCurrentScheme', function() {return 'chrome-extension:';}); assertEquals( fireauth.idp.ProviderId.FACEBOOK, fireauth.FacebookAuthProvider['PROVIDER_ID']); var authCredential = fireauth.FacebookAuthProvider.credential( 'facebookAccessToken'); assertEquals('facebookAccessToken', authCredential['accessToken']); assertEquals(fireauth.idp.ProviderId.FACEBOOK, authCredential['providerId']); assertEquals( fireauth.idp.SignInMethod.FACEBOOK, authCredential['signInMethod']); authCredential.getIdTokenProvider(rpcHandler); assertObjectEquals( { 'oauthAccessToken': 'facebookAccessToken', 'providerId': fireauth.idp.ProviderId.FACEBOOK, 'signInMethod': fireauth.idp.SignInMethod.FACEBOOK }, authCredential.toPlainObject()); // http://localhost should be used instead of the real current URL. assertRpcHandlerVerifyAssertion({ // requestUri should be http://localhost regardless of current URL. 'requestUri': 'http://localhost', 'postBody': 'access_token=facebookAccessToken&providerId=' + fireauth.idp.ProviderId.FACEBOOK }); } /** * Test GitHub Auth credential. */ function testGithubAuthCredential() { assertEquals( fireauth.idp.ProviderId.GITHUB, fireauth.GithubAuthProvider['PROVIDER_ID']); assertEquals( fireauth.idp.SignInMethod.GITHUB, fireauth.GithubAuthProvider['GITHUB_SIGN_IN_METHOD']); var authCredential = fireauth.GithubAuthProvider.credential( 'githubAccessToken'); assertEquals('githubAccessToken', authCredential['accessToken']); assertEquals(fireauth.idp.ProviderId.GITHUB, authCredential['providerId']); assertEquals( fireauth.idp.SignInMethod.GITHUB, authCredential['signInMethod']); authCredential.getIdTokenProvider(rpcHandler); assertObjectEquals( { 'oauthAccessToken': 'githubAccessToken', 'providerId': fireauth.idp.ProviderId.GITHUB, 'signInMethod':fireauth.idp.SignInMethod.GITHUB }, authCredential.toPlainObject()); // Test toJSON and fromJSON for current GitHub OAuthCredential. assertObjectEquals( authCredential, fireauth.OAuthCredential.fromJSON(authCredential.toPlainObject())); assertObjectEquals( authCredential, fireauth.AuthCredential.fromPlainObject(authCredential.toPlainObject())); assertRpcHandlerVerifyAssertion({ // requestUri should be http://localhost regardless of current URL. 'requestUri': 'http://localhost', 'postBody': 'access_token=githubAccessToken&providerId=' + fireauth.idp.ProviderId.GITHUB }); var provider = new fireauth.GithubAuthProvider(); // Should not throw an error. assertNotThrows(function() { fireauth.AuthProvider.checkIfOAuthSupported(provider); }); assertArrayEquals([], provider.getScopes()); provider.addScope('scope1'); assertArrayEquals(['scope1'], provider.getScopes()); provider.addScope('scope2'); assertArrayEquals(['scope1', 'scope2'], provider.getScopes()); assertEquals(fireauth.idp.ProviderId.GITHUB, provider['providerId']); assertTrue(provider['isOAuthProvider']); // Set OAuth custom parameters. provider.setCustomParameters({ // Valid GitHub OAuth 2.0 parameters. 'allow_signup': false, // Reserved parameters below should be filtered out. 'client_id': 'CLIENT_ID', 'response_type': 'token', 'scope': 'scope1', 'redirect_uri': 'https://www.evil.com', 'state': 'STATE' }); // Get custom parameters should only return the valid parameters. assertObjectEquals({ 'allow_signup': 'false' }, provider.getCustomParameters()); // Modify custom parameters. provider.setCustomParameters({ // Valid GitHub OAuth 2.0 parameters. 'allow_signup': true }); // Parameters should be updated. assertObjectEquals({ 'allow_signup': 'true' }, provider.getCustomParameters()); // Test Auth credential from response. assertObjectEquals( authCredential.toPlainObject(), fireauth.AuthProvider.getCredentialFromResponse({ 'providerId': 'github.com', 'oauthAccessToken': 'githubAccessToken' }).toPlainObject()); } function testGithubAuthProvider_localization() { var provider = new fireauth.GithubAuthProvider(); // Set default language on provider. provider.setDefaultLanguage('fr'); // Default language should be ignored as Github doesn't support localization. assertObjectEquals({}, provider.getCustomParameters()); // Set all possible language parameters. provider.setCustomParameters({ 'locale': 'ar', 'hl': 'ar', 'lang': 'ar' }); // All language parameters just piped through without the default. assertObjectEquals({ 'locale': 'ar', 'hl': 'ar', 'lang': 'ar' }, provider.getCustomParameters()); } function testOAuthProvider_localization() { var provider = new fireauth.OAuthProvider('yahoo.com'); // Set default language on provider. provider.setDefaultLanguage('fr'); // Default language should be ignored as generic providers don't support // default localization. assertObjectEquals({}, provider.getCustomParameters()); // Set all possible language parameters. provider.setCustomParameters({ 'locale': 'ar', 'hl': 'ar', 'lang': 'ar' }); // All language parameters just piped through without the default. assertObjectEquals({ 'locale': 'ar', 'hl': 'ar', 'lang': 'ar' }, provider.getCustomParameters()); } function testGithubAuthCredential_alternateConstructor() { var authCredential = fireauth.GithubAuthProvider.credential( {'accessToken': 'githubAccessToken'}); assertEquals('githubAccessToken', authCredential['accessToken']); assertEquals(fireauth.idp.ProviderId.GITHUB, authCredential['providerId']); assertObjectEquals( { 'oauthAccessToken': 'githubAccessToken', 'providerId': fireauth.idp.ProviderId.GITHUB, 'signInMethod':fireauth.idp.SignInMethod.GITHUB }, authCredential.toPlainObject()); // Missing token. var expectedError = new fireauth.AuthError( fireauth.authenum.Error.ARGUMENT_ERROR); var error = assertThrows(function() { fireauth.GithubAuthProvider.credential({}); }); assertEquals(expectedError.code, error.code); } function testGithubAuthProvider_chainedMethods() { // Test that method chaining works. var provider = new fireauth.GithubAuthProvider() .addScope('scope1') .addScope('scope2') .setCustomParameters({ 'allow_signup': false }) .addScope('scope3'); assertArrayEquals(['scope1', 'scope2', 'scope3'], provider.getScopes()); assertObjectEquals({ 'allow_signup': 'false' }, provider.getCustomParameters()); } function testGithubAuthCredential_linkToIdToken() { var authCredential = fireauth.GithubAuthProvider.credential( 'githubAccessToken'); authCredential.linkToIdToken(rpcHandler, 'myIdToken'); assertRpcHandlerVerifyAssertionForLinking({ // requestUri should be http://localhost regardless of current URL. 'requestUri': 'http://localhost', 'postBody': 'access_token=githubAccessToken&providerId=' + fireauth.idp.ProviderId.GITHUB, 'idToken': 'myIdToken' }); } function testGithubAuthCredential_matchIdTokenWithUid() { // Mock idToken parsing. initializeIdTokenMocks('ID_TOKEN', '1234'); var authCredential = fireauth.GithubAuthProvider.credential( 'githubAccessToken'); var p = authCredential.matchIdTokenWithUid(rpcHandler, '1234'); assertRpcHandlerVerifyAssertionForExisting({ // requestUri should be http://localhost regardless of current URL. 'requestUri': 'http://localhost', 'postBody': 'access_token=githubAccessToken&providerId=' + fireauth.idp.ProviderId.GITHUB, }); return p; } /** * Test Google Auth credential. */ function testGoogleAuthCredential() { assertEquals( fireauth.idp.ProviderId.GOOGLE, fireauth.GoogleAuthProvider['PROVIDER_ID']); assertEquals( fireauth.idp.SignInMethod.GOOGLE, fireauth.GoogleAuthProvider['GOOGLE_SIGN_IN_METHOD']); var authCredential = fireauth.GoogleAuthProvider.credential( 'googleIdToken', 'googleAccessToken'); assertEquals('googleIdToken', authCredential['idToken']); assertEquals('googleAccessToken', authCredential['accessToken']); assertEquals(fireauth.idp.ProviderId.GOOGLE, authCredential['providerId']); assertEquals( fireauth.idp.SignInMethod.GOOGLE, authCredential['signInMethod']); authCredential.getIdTokenProvider(rpcHandler); assertObjectEquals( { 'oauthAccessToken': 'googleAccessToken', 'oauthIdToken': 'googleIdToken', 'providerId': fireauth.idp.ProviderId.GOOGLE, 'signInMethod': fireauth.idp.SignInMethod.GOOGLE }, authCredential.toPlainObject()); // Test toJSON and fromJSON for current Google OAuthCredential. assertObjectEquals( authCredential, fireauth.OAuthCredential.fromJSON(authCredential.toPlainObject())); assertObjectEquals( authCredential, fireauth.AuthCredential.fromPlainObject(authCredential.toPlainObject())); assertRpcHandlerVerifyAssertion({ // requestUri should be http://localhost regardless of current URL. 'requestUri': 'http://localhost', 'postBody': 'id_token=googleIdToken&access_token=googleAccessToken&provi' + 'derId=' + fireauth.idp.ProviderId.GOOGLE }); var provider = new fireauth.GoogleAuthProvider(); // Should not throw an error. assertNotThrows(function() { fireauth.AuthProvider.checkIfOAuthSupported(provider); }); assertArrayEquals(['profile'], provider.getScopes()); provider.addScope('scope1'); assertArrayEquals(['profile', 'scope1'], provider.getScopes()); provider.addScope('scope2'); assertArrayEquals(['profile', 'scope1', 'scope2'], provider.getScopes()); assertEquals(fireauth.idp.ProviderId.GOOGLE, provider['providerId']); assertTrue(provider['isOAuthProvider']); // Set OAuth custom parameters. provider.setCustomParameters({ // Valid Google OAuth 2.0 parameters. 'login_hint': 'user@example.com', 'hd': 'example.com', 'hl': 'fr', 'prompt': 'consent', 'include_granted_scopes': true, // Reserved parameters below should be filtered out. 'client_id': 'CLIENT_ID', 'response_type': 'token', 'scope': 'scope1', 'redirect_uri': 'https://www.evil.com', 'state': 'STATE' }); // Get custom parameters should only return the valid parameters. assertObjectEquals({ 'login_hint': 'user@example.com', 'hd': 'example.com', 'hl': 'fr', 'prompt': 'consent', 'include_granted_scopes': 'true' }, provider.getCustomParameters()); // Modify custom parameters. provider.setCustomParameters({ // Valid Google OAuth 2.0 parameters. 'login_hint': 'user2@example.com' }); // Parameters should be updated. assertObjectEquals({ 'login_hint': 'user2@example.com' }, provider.getCustomParameters()); assertObjectEquals( authCredential.toPlainObject(), fireauth.AuthProvider.getCredentialFromResponse({ 'providerId': 'google.com',