LoginView.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. /**
  2. * Licensed Materials - Property of IBM
  3. * IBM Cognos Products: BI Glass
  4. * (C) Copyright IBM Corp. 2015, 2021
  5. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  6. */
  7. // jshint maxparams:12
  8. define(['baglass/app/ContentView', 'jquery', 'doT', 'underscore', 'toastr', 'baglass/nls/StringResources', 'text!./templates/LoginView.html', 'baglass/core-client/js/core-client/utils/Utils', 'baglass/utils/ThemeUtils', 'baglass/utils/Utils', '../ajax/CASimpleAuthentication', '../loading-indicator/src/js/LoadingIndicatorView', 'caglass/icons/ba-login-icon-bundle'], function (ContentView, $, dot, _, toastr, StringResources, template, Utils, ThemeUtils, GlassUtils, CAAuthentication, LoadingIndicatorView) {
  9. /**
  10. * This Class is a utility class to provide RESTFul api for glass
  11. */
  12. var LoginView = ContentView.extend({
  13. anonymousAllowed: false,
  14. _options: function _options() {
  15. var currentYear = new Date().getFullYear();
  16. return {
  17. buttonText: StringResources.get('signInButtonText'),
  18. anonymousText: StringResources.get('connectAnonymously'),
  19. anonymousAllowed: this.anonymousAllowed,
  20. backgroundImage: 'images/login_background.jpg',
  21. loginPromptBackground: 'images/loginPrompt_background.jpg',
  22. brandingText: '',
  23. loginLegalText: StringResources.get('loginLegalText', {
  24. 'fullYear': currentYear
  25. })
  26. };
  27. },
  28. /**
  29. * constructor
  30. * @options {object}
  31. */
  32. init: function init(options, appView) {
  33. LoginView.inherited('init', this, arguments);
  34. this.appView = appView;
  35. $.extend(this, options);
  36. this.canLogin = true;
  37. },
  38. remove: function remove() {
  39. this.$el.find('.signInBtn').off('primaryaction');
  40. this.$el.find('.userPromptInput').off('keyup');
  41. },
  42. _tryDirectLogin: function _tryDirectLogin() {
  43. return new Promise(function (resolve, reject) {
  44. if (GlassUtils.isUiPreview()) {
  45. reject(this._generatePreviewPromptInfo());
  46. } else {
  47. resolve(this._trySubmitCredentials());
  48. }
  49. }.bind(this));
  50. },
  51. _generatePreviewPromptInfo: function _generatePreviewPromptInfo() {
  52. return {
  53. displayObjects: [{
  54. 'name': 'CAMUsername',
  55. 'caption': StringResources.get('userPlaceholder') + ':',
  56. 'type': 'text'
  57. }, {
  58. 'name': 'CAMPassword',
  59. 'caption': StringResources.get('passPlaceholder') + ':',
  60. 'type': 'textnoecho'
  61. }]
  62. };
  63. },
  64. _trySubmitCredentials: function _trySubmitCredentials(loginPrompts) {
  65. if (!loginPrompts) {
  66. loginPrompts = {
  67. parameters: [{
  68. name: 'h_CAM_action',
  69. value: 'logonAs'
  70. }]
  71. };
  72. var queryString = '';
  73. if (this.origin) {
  74. queryString = this.origin.queryString;
  75. }
  76. loginPrompts.parameters = GlassUtils.getFilteredLoginParameters(this.glassContext, queryString, loginPrompts.parameters);
  77. }
  78. return this._getCAAuthentication().submitCredentials(this.glassContext, loginPrompts, this.origin);
  79. },
  80. render: function render() {
  81. if (this.appView && this.appView.content && this.appView.content.origin && this.appView.content.origin.authError && this.appView.content.origin.authError.displayObjects) {
  82. return this._renderPrompt(this.appView.content.origin.authError.displayObjects, this.appView.content.origin.authError);
  83. } else {
  84. return this._tryDirectLogin().then(function (response) {
  85. var authInfo = response.data;
  86. $(Utils.getCurrentWindow()).trigger('ca.loginSuccessful', authInfo);
  87. })["catch"](function (error) {
  88. return this._renderPrompt(error.displayObjects, error);
  89. }.bind(this));
  90. }
  91. },
  92. _renderPrompt: function _renderPrompt(displayObjects, error) {
  93. return ThemeUtils.getCurrentThemeValues(this.glassContext).then(function (response) {
  94. this._clearToasts();
  95. this.hiddenLoginPrompts = {
  96. 'parameters': []
  97. };
  98. this.anonymousAllowed = this.glassContext.authInfo && this.glassContext.authInfo.isAnonymous === true;
  99. var renderOptions = this._options();
  100. renderOptions.brandingText = _.escape(response['brandText']);
  101. this._brandingText = renderOptions.brandingText;
  102. var html = dot.template(template || '')(renderOptions);
  103. this.$el.append(html);
  104. this._$signInBtn = this.$el.find('button');
  105. this._$anonymousSession = this.$el.find('.anonymous');
  106. if (this._$anonymousSession[0] !== undefined) {
  107. this._$anonymousSession.on('primaryaction', function () {
  108. $(Utils.getCurrentWindow()).trigger('ca.loginSuccessful', {
  109. stayAnonymous: true
  110. });
  111. }.bind(this));
  112. }
  113. this._$signInBtn.on('primaryaction', $.proxy(this.onClick, this));
  114. this._saveHiddenLoginPrompts(displayObjects);
  115. this._updatePage(displayObjects);
  116. Utils.closeDialog();
  117. if (error.message) {
  118. this._showError(error.message);
  119. }
  120. return Promise.resolve(this);
  121. }.bind(this));
  122. },
  123. _saveHiddenLoginPrompts: function _saveHiddenLoginPrompts(displayObjectsArray) {
  124. _.each(displayObjectsArray, function (prompt) {
  125. if (prompt.type === 'hidden') {
  126. this._addToHiddenLoginPrompts(prompt);
  127. }
  128. }.bind(this));
  129. },
  130. _addToHiddenLoginPrompts: function _addToHiddenLoginPrompts(prompt) {
  131. var addPrompt = true;
  132. for (var i = 0; i < this.hiddenLoginPrompts.parameters.length; i++) {
  133. if (this.hiddenLoginPrompts.parameters[i].name === prompt.name) {
  134. this.hiddenLoginPrompts.parameters[i].value = prompt.value;
  135. addPrompt = false;
  136. }
  137. }
  138. if (addPrompt) {
  139. var hiddenPrompt = {
  140. 'name': prompt.name,
  141. 'value': prompt.value
  142. };
  143. this.hiddenLoginPrompts.parameters.push(hiddenPrompt);
  144. }
  145. },
  146. _createAppropriateCAMPrompt: function _createAppropriateCAMPrompt(prompt, $parent) {
  147. switch (prompt.type) {
  148. case 'text':
  149. case 'textnoecho':
  150. case 'verifytextnoecho':
  151. this._addTextInputField(prompt, $parent);
  152. break;
  153. case 'singleselect':
  154. this._addSelectInputField(prompt, $parent);
  155. break;
  156. case 'display':
  157. this._addLabel(prompt, $parent);
  158. break;
  159. }
  160. },
  161. _updatePage: function _updatePage(displayObjectsArray) {
  162. if (_.isEmpty(displayObjectsArray)) {
  163. this.canLogin = false;
  164. }
  165. var $parent = this.$el.find('.formContent');
  166. $parent.find('.camPrompts').empty();
  167. _.each(displayObjectsArray, function (prompt) {
  168. if (prompt.type !== 'hidden') {
  169. this._createAppropriateCAMPrompt(prompt, $parent);
  170. }
  171. }.bind(this));
  172. this._updateButton($parent);
  173. },
  174. _doNewPasswordEntriesMatch: function _doNewPasswordEntriesMatch() {
  175. var inputFields = this.$el.find('.newPasswordInput');
  176. if (inputFields.length < 1) {
  177. return true;
  178. } else {
  179. var value = $(inputFields[0]).val();
  180. for (var i = 1; i < inputFields.length; i++) {
  181. if ($(inputFields[i]).val() !== value) {
  182. return false;
  183. }
  184. }
  185. return true;
  186. }
  187. },
  188. _showProgress: function _showProgress(message) {
  189. var loading = new LoadingIndicatorView();
  190. var container = this.$el.find('.incorrectLoginText');
  191. var size = '40px';
  192. return loading.render({
  193. css: {
  194. height: size,
  195. width: size
  196. }
  197. }).then(function ($el) {
  198. container.removeAttr('role').html($el[0]);
  199. if (message) {
  200. Utils.activateAriaAlert(message);
  201. }
  202. });
  203. },
  204. _showError: function _showError(message) {
  205. this.$el.find('.incorrectLoginText').text(message);
  206. this.$el.find('.incorrectLoginText').attr('role', 'alert');
  207. },
  208. _getCAAuthentication: function _getCAAuthentication() {
  209. return new CAAuthentication();
  210. },
  211. /*
  212. * event handler
  213. */
  214. onClick: function onClick(evt, selectNamespace) {
  215. if (this._doNewPasswordEntriesMatch()) {
  216. if (selectNamespace) {
  217. this._showProgress();
  218. } else {
  219. this._showProgress(StringResources.get('loginInProgress'));
  220. }
  221. var shouldAddCAMNamespace = true;
  222. var loginPrompts = {
  223. 'parameters': []
  224. };
  225. loginPrompts.parameters = this.hiddenLoginPrompts.parameters.slice();
  226. var inputFields = this.$el.find('.userPromptInput');
  227. _.each(inputFields, function (inputField
  228. /*, key */
  229. ) {
  230. var $inputField = $(inputField);
  231. var prompt;
  232. if ($inputField.attr('name') === 'CAMNamespace') {
  233. for (var i = 0; i < loginPrompts.parameters.length; i++) {
  234. if (loginPrompts.parameters[i].name === 'CAMNamespace') {
  235. loginPrompts.parameters[i].value = $inputField.val();
  236. shouldAddCAMNamespace = false;
  237. }
  238. }
  239. if (shouldAddCAMNamespace) {
  240. prompt = {
  241. 'name': $inputField.attr('name'),
  242. 'value': $inputField.val()
  243. };
  244. loginPrompts.parameters.push(prompt);
  245. }
  246. } else {
  247. prompt = {
  248. 'name': $inputField.attr('name'),
  249. 'value': $inputField.val()
  250. };
  251. loginPrompts.parameters.push(prompt);
  252. }
  253. }.bind(this));
  254. return this._trySubmitCredentials(loginPrompts).then(function (authInfo) {
  255. Utils.activateAriaAlert(StringResources.get('loginSuccess'));
  256. $(Utils.getCurrentWindow()).trigger('ca.loginSuccessful', authInfo);
  257. }.bind(this))["catch"](function (error) {
  258. if (error.isExternalLogin) {
  259. var originInfo = this.origin ? this.origin : {};
  260. return this._getCAAuthentication().externalLogin(this.glassContext, error, originInfo).then(function (authInfo) {
  261. Utils.activateAriaAlert(StringResources.get('loginSuccess'));
  262. return this._getCAAuthentication()._processSuccessfulLogin(this.glassContext, authInfo, originInfo).then(function (authInfo) {
  263. $(Utils.getCurrentWindow()).trigger('ca.loginSuccessful', authInfo);
  264. });
  265. }.bind(this));
  266. } else {
  267. this.$el.find('.incorrectLoginText').html('');
  268. this._showError(error.message);
  269. this._saveHiddenLoginPrompts(error.displayObjects);
  270. this._updatePage(error.displayObjects);
  271. this.canLogin = true;
  272. return error;
  273. }
  274. }.bind(this));
  275. } else {
  276. this._showError(StringResources.get('newPasswordsDoNotMatch'));
  277. return Promise.reject(new Error());
  278. }
  279. },
  280. /*
  281. * event handler
  282. */
  283. onChange: function onChange(evt) {
  284. if (evt.keyCode === 13) {
  285. this.onClick();
  286. }
  287. },
  288. _addLabel: function _addLabel(prompt, $parent) {
  289. var $element = $('<div class="loginLabel">');
  290. if (prompt.name === 'CAMNamespaceDisplayName' || prompt.name === 'CAMUserNameForDisplay') {
  291. var nsList = $parent.find('select[name="CAMNamespace"]');
  292. if (nsList.length > 0 && prompt.name === 'CAMNamespaceDisplayName') {
  293. //For multiple namespaces, we'll just show the list
  294. return;
  295. } else {
  296. prompt.value = '<span>' + _.escape(prompt.value) + '</span>';
  297. $element.html(StringResources.get(prompt.name, {
  298. 'promptValue': prompt.value
  299. }));
  300. }
  301. } else {
  302. $element.text(StringResources.get('genericPrompt', {
  303. 'promptName': prompt.caption,
  304. 'promptValue': prompt.value
  305. }));
  306. }
  307. $parent.find('.camPrompts').append($element);
  308. },
  309. _addTextInputField: function _addTextInputField(prompt, $parent) {
  310. this.confirmNewPassword = false;
  311. var template = '<div class="textContainer flexDisplay flexRow flexCenter"><label for="{{=it.labelFor}}"><div class="imageContainer"></div></label><input type="text" id="{{=it.labelFor}}" class="authInput userPromptInput"></input></div>';
  312. if (prompt.type === 'text') {
  313. template = '<div class="textContainer flexDisplay flexRow flexCenter"><label for="{{=it.labelFor}}"><div class="imageContainer"></div></label><input type="text" id="{{=it.labelFor}}" name="{{=it.name}}" autocorrect="off" autocapitalize="off" placeholder="{{=it.placeHolder}}" aria-label="{{=it.label}}" class="authInput userPromptInput"></input></div>';
  314. } else if (prompt.type === 'textnoecho') {
  315. template = '<div class="textContainer flexDisplay flexRow flexCenter"><label for="{{=it.labelFor}}"><div class="imageContainer"></div></label><input type="password" id="{{=it.labelFor}}" name="{{=it.name}}" placeholder="{{=it.placeHolder}}" aria-label="{{=it.label}}" class="authInput userPromptInput"></input></div>';
  316. } else if (prompt.type === 'verifytextnoecho') {
  317. template = '<div class="textContainer flexDisplay flexRow flexCenter"><label for="{{=it.labelFor}}"><div class="imageContainer"></div></label><input type="password" id="{{=it.labelFor}}" name="{{=it.name}}" placeholder="{{=it.placeHolder}}" aria-label="{{=it.label}}" class="authInput userPromptInput newPasswordInput"></input></div>';
  318. this.confirmNewPassword = true;
  319. this.buttonText = StringResources.get('changePassword');
  320. }
  321. var title = prompt.caption.substring(0, prompt.caption.length - 1);
  322. var html = dot.template(template)({
  323. name: prompt.name,
  324. placeHolder: title,
  325. label: title,
  326. labelFor: prompt.name
  327. });
  328. var $element = $(html);
  329. var $imageElement = $element.find('.imageContainer');
  330. var promptName = prompt.name;
  331. if (promptName.indexOf('Password') !== -1) {
  332. promptName = 'CAMPassword';
  333. }
  334. Utils.setIcon($imageElement, 'login-' + promptName, title);
  335. $parent.find('.camPrompts').append($element);
  336. $element.find('input').on('input keyup', $.proxy(this.onChange, this));
  337. },
  338. _addSelectInputField: function _addSelectInputField(prompt, $parent) {
  339. var template = '<div class="selectContainer"><div class="imageContainer"></div><select name="{{=it.name}}" aria-label="{{=it.label}}" class="authInput userPromptInput"></select></div>';
  340. var title = prompt.caption.substring(0, prompt.caption.length);
  341. var html = dot.template(template)({
  342. name: prompt.name,
  343. label: title
  344. });
  345. var $element = $(html);
  346. var $imageElement = $element.find('.imageContainer');
  347. Utils.setIcon($imageElement, 'login-' + prompt.name, title);
  348. var promptOptions = prompt.promptOptions;
  349. var attributes;
  350. for (var j = 0; j < promptOptions.length; j++) {
  351. var text = promptOptions[j].value;
  352. var value = promptOptions[j].id;
  353. var isDefault = promptOptions[j].isDefault;
  354. attributes = {
  355. value: value,
  356. text: text
  357. };
  358. if (isDefault === true && prompt.name !== 'CAMNamespace') {
  359. attributes.selected = 'selected';
  360. }
  361. $element.find('select').append($('<option>', attributes));
  362. }
  363. if (prompt.name === 'CAMNamespace') {
  364. attributes = {
  365. value: StringResources.get('selectNamespace'),
  366. text: StringResources.get('selectNamespace')
  367. };
  368. attributes.selected = 'selected';
  369. $element.find('select').append($('<option>', attributes));
  370. this.canLogin = false;
  371. $element.on('change', $.proxy(function (event) {
  372. //This hard coded prompt becomes necessary because we have no other way of saving this in the state, if we
  373. //reset all the hidden prompts. This makes sense as this prompt is ALWAYS required by CAM, when trying to sign in.
  374. var actionPrompt = {
  375. 'name': 'h_CAM_action',
  376. 'value': 'logonAs'
  377. };
  378. this._addToHiddenLoginPrompts(actionPrompt);
  379. this.buttonText = StringResources.get('signInButtonText');
  380. this.canLogin = true;
  381. $parent.find('.camPrompts').empty();
  382. $parent.find('.incorrectLoginText').html('');
  383. $parent.find('.incorrectLoginText').removeAttr('role');
  384. $('select[name="CAMNamespace"]').find('option[value="' + StringResources.get('selectNamespace') + '"]').remove();
  385. this.onClick(event, true);
  386. }, this));
  387. $parent.find('.nameSpacePrompt').append($element);
  388. } else {
  389. $parent.find('.camPrompts').append($element);
  390. }
  391. },
  392. _updateButton: function _updateButton($parent) {
  393. if (this.canLogin) {
  394. $parent.find('.buttonPane').find('button').html(this.buttonText);
  395. $parent.find('.buttonPane').find('button').removeClass('hidden');
  396. } else {
  397. $parent.find('.buttonPane').find('button').addClass('hidden');
  398. }
  399. },
  400. _clearToasts: function _clearToasts() {
  401. toastr.options.hideDuration = 1;
  402. toastr.clear();
  403. },
  404. getTitle: function getTitle() {
  405. return this._brandingText || '';
  406. }
  407. });
  408. return LoginView;
  409. });
  410. //# sourceMappingURL=LoginView.js.map