@webex/plugin-authorization-browser-first-party 1.150.0 → 1.151.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -132,7 +132,7 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
132
132
 
133
133
  var codeVerifier = this.webex.getWindow().sessionStorage.getItem(OAUTH2_CODE_VERIFIER);
134
134
  this.webex.getWindow().sessionStorage.removeItem(OAUTH2_CODE_VERIFIER);
135
- var email = location.query.state.email;
135
+ var emailhash = location.query.state.emailhash;
136
136
 
137
137
  this._verifySecurityToken(location.query);
138
138
 
@@ -141,7 +141,7 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
141
141
 
142
142
  process.nextTick(function () {
143
143
  _this.webex.internal.services.collectPreauthCatalog({
144
- email: email
144
+ emailhash: emailhash
145
145
  }).catch(function () {
146
146
  return _promise.default.resolve();
147
147
  }).then(function () {
@@ -165,9 +165,17 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
165
165
  */
166
166
  initiateLogin: function initiateLogin() {
167
167
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
168
+ options = (0, _cloneDeep2.default)(options);
169
+
170
+ if (options.email) {
171
+ options.emailHash = _cryptoJs.default.SHA256(options.email).toString();
172
+ }
173
+
174
+ delete options.email;
168
175
  options.state = options.state || {};
169
- options.state.csrf_token = this._generateSecurityToken();
170
- options.state.email = options.email;
176
+ options.state.csrf_token = this._generateSecurityToken(); // catalog uses emailhash and redirectCI uses emailHash
177
+
178
+ options.state.emailhash = options.emailHash;
171
179
  options.code_challenge = this._generateCodeChallenge();
172
180
  options.code_challenge_method = 'S256';
173
181
  return this.initiateAuthorizationCodeGrant(options);
@@ -371,7 +379,7 @@ var Authorization = _webexCore.WebexPlugin.extend((_dec = (0, _common.whileInFli
371
379
  throw new Error("CSRF token ".concat(token, " does not match stored token ").concat(sessionToken));
372
380
  }
373
381
  },
374
- version: "1.150.0"
382
+ version: "1.151.2"
375
383
  }, ((0, _applyDecoratedDescriptor2.default)(_obj, "initiateAuthorizationCodeGrant", [_dec], (0, _getOwnPropertyDescriptor.default)(_obj, "initiateAuthorizationCodeGrant"), _obj), (0, _applyDecoratedDescriptor2.default)(_obj, "requestAuthorizationCodeGrant", [_dec2, _common.oneFlight], (0, _getOwnPropertyDescriptor.default)(_obj, "requestAuthorizationCodeGrant"), _obj)), _obj)));
376
384
 
377
385
  var _default = Authorization;
@@ -1 +1 @@
1
- {"version":3,"sources":["authorization.js"],"names":["lodash","require","OAUTH2_CSRF_TOKEN","OAUTH2_CODE_VERIFIER","Authorization","WebexPlugin","extend","derived","isAuthenticating","deps","fn","isAuthorizing","session","default","type","ready","namespace","initialize","attrs","ret","prototype","location","url","parse","webex","getWindow","href","_checkForErrors","code","query","state","JSON","base64","decode","codeVerifier","sessionStorage","getItem","removeItem","email","_verifySecurityToken","_cleanUrl","process","nextTick","internal","services","collectPreauthCatalog","catch","resolve","then","requestAuthorizationCodeGrant","initiateLogin","options","csrf_token","_generateSecurityToken","code_challenge","_generateCodeChallenge","code_challenge_method","initiateAuthorizationCodeGrant","logger","info","credentials","buildLoginUrl","response_type","logout","noRedirect","buildLogoutUrl","reject","Error","form","grant_type","redirect_uri","config","self_contained_token","code_verifier","request","method","uri","tokenUrl","auth","user","client_id","pass","client_secret","sendImmediately","shouldRefreshAccessToken","res","set","supertoken","body","statusCode","ErrorConstructor","grantErrors","select","error","_res","history","replaceState","encode","search","querystring","stringify","format","safeCharacterMap","base64url","_safe_map","times","random","length","join","codeChallenge","CryptoJS","SHA256","toString","setItem","token","uuid","v4","sessionToken","oneFlight"],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\n/* eslint camelcase: [0] */\n\nimport querystring from 'querystring';\nimport url from 'url';\n\nimport {base64, oneFlight, whileInFlight} from '@webex/common';\nimport {grantErrors, WebexPlugin} from '@webex/webex-core';\nimport {cloneDeep, isEmpty, omit} from 'lodash';\nimport uuid from 'uuid';\nimport base64url from 'crypto-js/enc-base64url';\nimport CryptoJS from 'crypto-js';\n\n// Necessary to require lodash this way in order to stub\n// methods in the unit test\nconst lodash = require('lodash');\n\nconst OAUTH2_CSRF_TOKEN = 'oauth2-csrf-token';\nconst OAUTH2_CODE_VERIFIER = 'oauth2-code-verifier';\n\n/**\n * Browser support for OAuth2. Automatically parses the URL query for an\n * authorization code\n *\n * Use of this plugin for anything other than the Webex Web Client is strongly\n * discouraged and may be broken at any time\n * @class\n * @name AuthorizationBrowserFirstParty\n * @private\n */\nconst Authorization = WebexPlugin.extend({\n derived: {\n /**\n * Alias of {@link AuthorizationBrowserFirstParty#isAuthorizing}\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @type {boolean}\n */\n isAuthenticating: {\n deps: ['isAuthorizing'],\n fn() {\n return this.isAuthorizing;\n }\n }\n },\n\n session: {\n /**\n * Indicates if an Authorization Code exchange is inflight\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @type {boolean}\n */\n isAuthorizing: {\n default: false,\n type: 'boolean'\n },\n ready: {\n default: false,\n type: 'boolean'\n }\n },\n\n namespace: 'Credentials',\n\n /**\n * Initializer\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @private\n * @returns {Authorization}\n */\n // eslint-disable-next-line complexity\n initialize(...attrs) {\n const ret = Reflect.apply(WebexPlugin.prototype.initialize, this, attrs);\n const location = url.parse(this.webex.getWindow().location.href, true);\n\n this._checkForErrors(location);\n\n const {code} = location.query;\n\n if (!code) {\n this.ready = true;\n\n return ret;\n }\n\n if (location.query.state) {\n location.query.state = JSON.parse(base64.decode(location.query.state));\n }\n else {\n location.query.state = {};\n }\n\n const codeVerifier = this.webex.getWindow().sessionStorage.getItem(OAUTH2_CODE_VERIFIER);\n\n this.webex.getWindow().sessionStorage.removeItem(OAUTH2_CODE_VERIFIER);\n\n\n const {email} = location.query.state;\n\n this._verifySecurityToken(location.query);\n this._cleanUrl(location);\n\n // Wait until nextTick in case `credentials` hasn't initialized yet\n process.nextTick(() => {\n this.webex.internal.services.collectPreauthCatalog({email})\n .catch(() => Promise.resolve())\n .then(() => this.requestAuthorizationCodeGrant({code, codeVerifier}))\n .then(() => {\n this.ready = true;\n });\n });\n\n\n return ret;\n },\n\n /**\n * Kicks off an oauth flow\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @returns {Promise}\n */\n initiateLogin(options = {}) {\n options.state = options.state || {};\n options.state.csrf_token = this._generateSecurityToken();\n options.state.email = options.email;\n\n options.code_challenge = this._generateCodeChallenge();\n options.code_challenge_method = 'S256';\n\n\n return this.initiateAuthorizationCodeGrant(options);\n },\n\n @whileInFlight('isAuthorizing')\n /**\n * Kicks off the Implicit Code grant flow. Typically called via\n * {@link AuthorizationBrowserFirstParty#initiateLogin}\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @returns {Promise}\n */\n initiateAuthorizationCodeGrant(options) {\n this.logger.info('authorization: initiating authorization code grant flow');\n this.webex.getWindow().location = this.webex.credentials.buildLoginUrl(Object.assign({response_type: 'code'}, options));\n\n return Promise.resolve();\n },\n\n /**\n * Called by {@link WebexCore#logout()}. Redirects to the logout page\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @param {boolean} options.noRedirect if true, does not redirect\n * @returns {Promise}\n */\n logout(options = {}) {\n if (!options.noRedirect) {\n this.webex.getWindow().location = this.webex.credentials.buildLogoutUrl(options);\n }\n },\n\n\n @whileInFlight('isAuthorizing')\n @oneFlight\n /**\n * Exchanges an authorization code for an access token\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @param {Object} options.code\n * @returns {Promise}\n */\n requestAuthorizationCodeGrant(options = {}) {\n this.logger.info('credentials: requesting authorization code grant');\n\n if (!options.code) {\n return Promise.reject(new Error('`options.code` is required'));\n }\n\n const form = {\n grant_type: 'authorization_code',\n redirect_uri: this.config.redirect_uri,\n code: options.code,\n self_contained_token: true\n };\n\n if (options.codeVerifier) {\n form.code_verifier = options.codeVerifier;\n }\n\n return this.webex.request({\n method: 'POST',\n uri: this.config.tokenUrl,\n form,\n auth: {\n user: this.config.client_id,\n pass: this.config.client_secret,\n sendImmediately: true\n },\n shouldRefreshAccessToken: false\n })\n .then((res) => {\n this.webex.credentials.set({supertoken: res.body});\n })\n .catch((res) => {\n if (res.statusCode !== 400) {\n return Promise.reject(res);\n }\n\n const ErrorConstructor = grantErrors.select(res.body.error);\n\n return Promise.reject(new ErrorConstructor(res._res || res));\n });\n },\n\n /**\n * Checks if the result of the login redirect contains an error string\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} location\n * @private\n * @returns {Promise}\n */\n _checkForErrors(location) {\n const {query} = location;\n\n if (query && query.error) {\n const ErrorConstructor = grantErrors.select(query.error);\n\n throw new ErrorConstructor(query);\n }\n },\n\n /**\n * Removes no-longer needed values from the url (access token, csrf token, etc)\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} location\n * @private\n * @returns {Promise}\n */\n _cleanUrl(location) {\n location = cloneDeep(location);\n if (this.webex.getWindow().history && this.webex.getWindow().history.replaceState) {\n Reflect.deleteProperty(location.query, 'code');\n if (isEmpty(omit(location.query.state, 'csrf_token'))) {\n Reflect.deleteProperty(location.query, 'state');\n }\n else {\n location.query.state = base64.encode(JSON.stringify(omit(location.query.state, 'csrf_token')));\n }\n location.search = querystring.stringify(location.query);\n Reflect.deleteProperty(location, 'query');\n this.webex.getWindow().history.replaceState({}, null, url.format(location));\n }\n },\n\n /**\n * Generates PKCE code verifier and code challenge and sets the the code verifier in sessionStorage\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @private\n * @returns {string}\n */\n _generateCodeChallenge() {\n this.logger.info('authorization: generating PKCE code challenge');\n\n // eslint-disable-next-line no-underscore-dangle\n const safeCharacterMap = base64url._safe_map;\n\n const codeVerifier = lodash.times(\n 128,\n () => safeCharacterMap[lodash.random(0, safeCharacterMap.length - 1)]\n ).join('');\n\n const codeChallenge = CryptoJS.SHA256(codeVerifier).toString(base64url);\n\n this.webex.getWindow().sessionStorage.setItem(\n OAUTH2_CODE_VERIFIER, codeVerifier\n );\n\n return codeChallenge;\n },\n\n /**\n * Generates a CSRF token and sticks in in sessionStorage\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @private\n * @returns {Promise}\n */\n _generateSecurityToken() {\n this.logger.info('authorization: generating csrf token');\n\n const token = uuid.v4();\n\n this.webex.getWindow().sessionStorage.setItem('oauth2-csrf-token', token);\n\n return token;\n },\n\n /**\n * Checks if the CSRF token in sessionStorage is the same as the one returned\n * in the url.\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} query\n * @private\n * @returns {Promise}\n */\n _verifySecurityToken(query) {\n const sessionToken = this.webex.getWindow().sessionStorage.getItem(OAUTH2_CSRF_TOKEN);\n\n this.webex.getWindow().sessionStorage.removeItem(OAUTH2_CSRF_TOKEN);\n if (!sessionToken) {\n return;\n }\n\n if (!query.state) {\n throw new Error(`Expected CSRF token ${sessionToken}, but not found in redirect query`);\n }\n\n if (!query.state.csrf_token) {\n throw new Error(`Expected CSRF token ${sessionToken}, but not found in redirect query`);\n }\n\n const token = query.state.csrf_token;\n\n if (token !== sessionToken) {\n throw new Error(`CSRF token ${token} does not match stored token ${sessionToken}`);\n }\n }\n});\n\nexport default Authorization;\n"]}
1
+ {"version":3,"sources":["authorization.js"],"names":["lodash","require","OAUTH2_CSRF_TOKEN","OAUTH2_CODE_VERIFIER","Authorization","WebexPlugin","extend","derived","isAuthenticating","deps","fn","isAuthorizing","session","default","type","ready","namespace","initialize","attrs","ret","prototype","location","url","parse","webex","getWindow","href","_checkForErrors","code","query","state","JSON","base64","decode","codeVerifier","sessionStorage","getItem","removeItem","emailhash","_verifySecurityToken","_cleanUrl","process","nextTick","internal","services","collectPreauthCatalog","catch","resolve","then","requestAuthorizationCodeGrant","initiateLogin","options","email","emailHash","CryptoJS","SHA256","toString","csrf_token","_generateSecurityToken","code_challenge","_generateCodeChallenge","code_challenge_method","initiateAuthorizationCodeGrant","logger","info","credentials","buildLoginUrl","response_type","logout","noRedirect","buildLogoutUrl","reject","Error","form","grant_type","redirect_uri","config","self_contained_token","code_verifier","request","method","uri","tokenUrl","auth","user","client_id","pass","client_secret","sendImmediately","shouldRefreshAccessToken","res","set","supertoken","body","statusCode","ErrorConstructor","grantErrors","select","error","_res","history","replaceState","encode","search","querystring","stringify","format","safeCharacterMap","base64url","_safe_map","times","random","length","join","codeChallenge","setItem","token","uuid","v4","sessionToken","oneFlight"],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.\n */\n\n/* eslint camelcase: [0] */\n\nimport querystring from 'querystring';\nimport url from 'url';\n\nimport {base64, oneFlight, whileInFlight} from '@webex/common';\nimport {grantErrors, WebexPlugin} from '@webex/webex-core';\nimport {cloneDeep, isEmpty, omit} from 'lodash';\nimport uuid from 'uuid';\nimport base64url from 'crypto-js/enc-base64url';\nimport CryptoJS from 'crypto-js';\n\n// Necessary to require lodash this way in order to stub\n// methods in the unit test\nconst lodash = require('lodash');\n\nconst OAUTH2_CSRF_TOKEN = 'oauth2-csrf-token';\nconst OAUTH2_CODE_VERIFIER = 'oauth2-code-verifier';\n\n/**\n * Browser support for OAuth2. Automatically parses the URL query for an\n * authorization code\n *\n * Use of this plugin for anything other than the Webex Web Client is strongly\n * discouraged and may be broken at any time\n * @class\n * @name AuthorizationBrowserFirstParty\n * @private\n */\nconst Authorization = WebexPlugin.extend({\n derived: {\n /**\n * Alias of {@link AuthorizationBrowserFirstParty#isAuthorizing}\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @type {boolean}\n */\n isAuthenticating: {\n deps: ['isAuthorizing'],\n fn() {\n return this.isAuthorizing;\n }\n }\n },\n\n session: {\n /**\n * Indicates if an Authorization Code exchange is inflight\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @type {boolean}\n */\n isAuthorizing: {\n default: false,\n type: 'boolean'\n },\n ready: {\n default: false,\n type: 'boolean'\n }\n },\n\n namespace: 'Credentials',\n\n /**\n * Initializer\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @private\n * @returns {Authorization}\n */\n // eslint-disable-next-line complexity\n initialize(...attrs) {\n const ret = Reflect.apply(WebexPlugin.prototype.initialize, this, attrs);\n const location = url.parse(this.webex.getWindow().location.href, true);\n\n this._checkForErrors(location);\n\n const {code} = location.query;\n\n if (!code) {\n this.ready = true;\n\n return ret;\n }\n\n if (location.query.state) {\n location.query.state = JSON.parse(base64.decode(location.query.state));\n }\n else {\n location.query.state = {};\n }\n\n const codeVerifier = this.webex.getWindow().sessionStorage.getItem(OAUTH2_CODE_VERIFIER);\n\n this.webex.getWindow().sessionStorage.removeItem(OAUTH2_CODE_VERIFIER);\n\n\n const {emailhash} = location.query.state;\n\n this._verifySecurityToken(location.query);\n this._cleanUrl(location);\n\n // Wait until nextTick in case `credentials` hasn't initialized yet\n process.nextTick(() => {\n this.webex.internal.services.collectPreauthCatalog({emailhash})\n .catch(() => Promise.resolve())\n .then(() => this.requestAuthorizationCodeGrant({code, codeVerifier}))\n .then(() => {\n this.ready = true;\n });\n });\n\n\n return ret;\n },\n\n /**\n * Kicks off an oauth flow\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @returns {Promise}\n */\n initiateLogin(options = {}) {\n options = cloneDeep(options);\n if (options.email) {\n options.emailHash = CryptoJS.SHA256(options.email).toString();\n }\n delete options.email;\n options.state = options.state || {};\n options.state.csrf_token = this._generateSecurityToken();\n // catalog uses emailhash and redirectCI uses emailHash\n options.state.emailhash = options.emailHash;\n\n options.code_challenge = this._generateCodeChallenge();\n options.code_challenge_method = 'S256';\n\n\n return this.initiateAuthorizationCodeGrant(options);\n },\n\n @whileInFlight('isAuthorizing')\n /**\n * Kicks off the Implicit Code grant flow. Typically called via\n * {@link AuthorizationBrowserFirstParty#initiateLogin}\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @returns {Promise}\n */\n initiateAuthorizationCodeGrant(options) {\n this.logger.info('authorization: initiating authorization code grant flow');\n this.webex.getWindow().location = this.webex.credentials.buildLoginUrl(Object.assign({response_type: 'code'}, options));\n\n return Promise.resolve();\n },\n\n /**\n * Called by {@link WebexCore#logout()}. Redirects to the logout page\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @param {boolean} options.noRedirect if true, does not redirect\n * @returns {Promise}\n */\n logout(options = {}) {\n if (!options.noRedirect) {\n this.webex.getWindow().location = this.webex.credentials.buildLogoutUrl(options);\n }\n },\n\n\n @whileInFlight('isAuthorizing')\n @oneFlight\n /**\n * Exchanges an authorization code for an access token\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} options\n * @param {Object} options.code\n * @returns {Promise}\n */\n requestAuthorizationCodeGrant(options = {}) {\n this.logger.info('credentials: requesting authorization code grant');\n\n if (!options.code) {\n return Promise.reject(new Error('`options.code` is required'));\n }\n\n const form = {\n grant_type: 'authorization_code',\n redirect_uri: this.config.redirect_uri,\n code: options.code,\n self_contained_token: true\n };\n\n if (options.codeVerifier) {\n form.code_verifier = options.codeVerifier;\n }\n\n return this.webex.request({\n method: 'POST',\n uri: this.config.tokenUrl,\n form,\n auth: {\n user: this.config.client_id,\n pass: this.config.client_secret,\n sendImmediately: true\n },\n shouldRefreshAccessToken: false\n })\n .then((res) => {\n this.webex.credentials.set({supertoken: res.body});\n })\n .catch((res) => {\n if (res.statusCode !== 400) {\n return Promise.reject(res);\n }\n\n const ErrorConstructor = grantErrors.select(res.body.error);\n\n return Promise.reject(new ErrorConstructor(res._res || res));\n });\n },\n\n /**\n * Checks if the result of the login redirect contains an error string\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} location\n * @private\n * @returns {Promise}\n */\n _checkForErrors(location) {\n const {query} = location;\n\n if (query && query.error) {\n const ErrorConstructor = grantErrors.select(query.error);\n\n throw new ErrorConstructor(query);\n }\n },\n\n /**\n * Removes no-longer needed values from the url (access token, csrf token, etc)\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} location\n * @private\n * @returns {Promise}\n */\n _cleanUrl(location) {\n location = cloneDeep(location);\n if (this.webex.getWindow().history && this.webex.getWindow().history.replaceState) {\n Reflect.deleteProperty(location.query, 'code');\n if (isEmpty(omit(location.query.state, 'csrf_token'))) {\n Reflect.deleteProperty(location.query, 'state');\n }\n else {\n location.query.state = base64.encode(JSON.stringify(omit(location.query.state, 'csrf_token')));\n }\n location.search = querystring.stringify(location.query);\n Reflect.deleteProperty(location, 'query');\n this.webex.getWindow().history.replaceState({}, null, url.format(location));\n }\n },\n\n /**\n * Generates PKCE code verifier and code challenge and sets the the code verifier in sessionStorage\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @private\n * @returns {string}\n */\n _generateCodeChallenge() {\n this.logger.info('authorization: generating PKCE code challenge');\n\n // eslint-disable-next-line no-underscore-dangle\n const safeCharacterMap = base64url._safe_map;\n\n const codeVerifier = lodash.times(\n 128,\n () => safeCharacterMap[lodash.random(0, safeCharacterMap.length - 1)]\n ).join('');\n\n const codeChallenge = CryptoJS.SHA256(codeVerifier).toString(base64url);\n\n this.webex.getWindow().sessionStorage.setItem(\n OAUTH2_CODE_VERIFIER, codeVerifier\n );\n\n return codeChallenge;\n },\n\n /**\n * Generates a CSRF token and sticks in in sessionStorage\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @private\n * @returns {Promise}\n */\n _generateSecurityToken() {\n this.logger.info('authorization: generating csrf token');\n\n const token = uuid.v4();\n\n this.webex.getWindow().sessionStorage.setItem('oauth2-csrf-token', token);\n\n return token;\n },\n\n /**\n * Checks if the CSRF token in sessionStorage is the same as the one returned\n * in the url.\n * @instance\n * @memberof AuthorizationBrowserFirstParty\n * @param {Object} query\n * @private\n * @returns {Promise}\n */\n _verifySecurityToken(query) {\n const sessionToken = this.webex.getWindow().sessionStorage.getItem(OAUTH2_CSRF_TOKEN);\n\n this.webex.getWindow().sessionStorage.removeItem(OAUTH2_CSRF_TOKEN);\n if (!sessionToken) {\n return;\n }\n\n if (!query.state) {\n throw new Error(`Expected CSRF token ${sessionToken}, but not found in redirect query`);\n }\n\n if (!query.state.csrf_token) {\n throw new Error(`Expected CSRF token ${sessionToken}, but not found in redirect query`);\n }\n\n const token = query.state.csrf_token;\n\n if (token !== sessionToken) {\n throw new Error(`CSRF token ${token} does not match stored token ${sessionToken}`);\n }\n }\n});\n\nexport default Authorization;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webex/plugin-authorization-browser-first-party",
3
- "version": "1.150.0",
3
+ "version": "1.151.2",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "author": "Ian W. Remmel <iremmel@cisco.com>",
@@ -17,9 +17,9 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@babel/runtime-corejs2": "^7.14.8",
20
- "@webex/webex-core": "1.150.0",
20
+ "@webex/webex-core": "1.151.2",
21
21
  "lodash": "^4.17.21",
22
- "@webex/common": "1.150.0",
22
+ "@webex/common": "1.151.2",
23
23
  "uuid": "^3.3.2",
24
24
  "crypto-js": "^4.1.1",
25
25
  "envify": "^4.1.0"
@@ -100,14 +100,14 @@ const Authorization = WebexPlugin.extend({
100
100
  this.webex.getWindow().sessionStorage.removeItem(OAUTH2_CODE_VERIFIER);
101
101
 
102
102
 
103
- const {email} = location.query.state;
103
+ const {emailhash} = location.query.state;
104
104
 
105
105
  this._verifySecurityToken(location.query);
106
106
  this._cleanUrl(location);
107
107
 
108
108
  // Wait until nextTick in case `credentials` hasn't initialized yet
109
109
  process.nextTick(() => {
110
- this.webex.internal.services.collectPreauthCatalog({email})
110
+ this.webex.internal.services.collectPreauthCatalog({emailhash})
111
111
  .catch(() => Promise.resolve())
112
112
  .then(() => this.requestAuthorizationCodeGrant({code, codeVerifier}))
113
113
  .then(() => {
@@ -127,9 +127,15 @@ const Authorization = WebexPlugin.extend({
127
127
  * @returns {Promise}
128
128
  */
129
129
  initiateLogin(options = {}) {
130
+ options = cloneDeep(options);
131
+ if (options.email) {
132
+ options.emailHash = CryptoJS.SHA256(options.email).toString();
133
+ }
134
+ delete options.email;
130
135
  options.state = options.state || {};
131
136
  options.state.csrf_token = this._generateSecurityToken();
132
- options.state.email = options.email;
137
+ // catalog uses emailhash and redirectCI uses emailHash
138
+ options.state.emailhash = options.emailHash;
133
139
 
134
140
  options.code_challenge = this._generateCodeChallenge();
135
141
  options.code_challenge_method = 'S256';
@@ -259,6 +259,27 @@ browserOnly(describe)('plugin-authorization-browser-first-party', () => {
259
259
  });
260
260
  });
261
261
 
262
+ it('adds emailHash', () => {
263
+ const webex = makeWebex(undefined, undefined, {
264
+ credentials: {
265
+ clientType: 'confidential'
266
+ }
267
+ });
268
+
269
+ const expectedEmailHash = '73062d872926c2a556f17b36f50e328ddf9bff9d403939bd14b6c3b7f5a33fc2';
270
+
271
+ sinon.spy(webex.authorization, 'initiateAuthorizationCodeGrant');
272
+
273
+ return webex.authorization.initiateLogin({email: 'test@email.com'})
274
+ .then(() => {
275
+ assert.called(webex.authorization.initiateAuthorizationCodeGrant);
276
+ const grantOptions = webex.authorization.initiateAuthorizationCodeGrant.getCall(0).args[0];
277
+
278
+ assert.equal(grantOptions.emailHash, expectedEmailHash);
279
+ assert.isUndefined(grantOptions.email);
280
+ });
281
+ });
282
+
262
283
  it('sets #isAuthorizing', () => {
263
284
  const webex = makeWebex(undefined, undefined, {
264
285
  credentials: {