addSecurityConfigs.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. var App = require('app');
  19. var objectUtils = require('utils/object_utils');
  20. /**
  21. * Mixin for loading and setting secure configs
  22. *
  23. * @type {Ember.Mixin}
  24. */
  25. App.AddSecurityConfigs = Em.Mixin.create({
  26. kerberosDescriptor: {},
  27. kerberosDescriptorProperties: require('data/HDP2/kerberos_descriptor_properties'),
  28. /**
  29. * security configs, which values should be modified after APPLY CONFIGURATIONS stage
  30. */
  31. secureConfigs: [
  32. {
  33. name: 'zookeeper_principal_name',
  34. serviceName: 'ZOOKEEPER'
  35. },
  36. {
  37. name: 'knox_principal_name',
  38. serviceName: 'KNOX'
  39. },
  40. {
  41. name: 'storm_principal_name',
  42. serviceName: 'STORM'
  43. },
  44. {
  45. name: 'nimbus_principal_name',
  46. serviceName: 'STORM'
  47. }
  48. ],
  49. /**
  50. * Store status of kerberos descriptor located in cluster artifacts.
  51. * This status needed for Add Service Wizard to select appropriate method to create
  52. * or update descriptor.
  53. *
  54. * @param {Boolean} isExists <code>true</code> if cluster descriptor present
  55. */
  56. storeClusterDescriptorStatus: function(isExists) {
  57. if (this.get('isWithinAddService')) {
  58. this.get('wizardController').setDBProperty('isClusterDescriptorExists', isExists);
  59. }
  60. },
  61. /**
  62. *
  63. * @param {object[]} items - stack descriptor json response
  64. * @returns {App.ServiceConfigProperty[]}
  65. */
  66. createServicesStackDescriptorConfigs: function (items) {
  67. var self = this;
  68. var configs = [];
  69. var clusterConfigs = [];
  70. var kerberosDescriptor = Em.get(items, 'KerberosDescriptor.kerberos_descriptor');
  71. this.set('kerberosDescriptor', kerberosDescriptor);
  72. // generate configs for root level properties object, currently realm, keytab_dir
  73. clusterConfigs = clusterConfigs.concat(this.expandKerberosStackDescriptorProps(kerberosDescriptor.properties, 'Cluster', 'stackConfigs'));
  74. // generate configs for root level identities object, currently spnego property
  75. clusterConfigs = clusterConfigs.concat(this.createConfigsByIdentities(kerberosDescriptor.identities, 'Cluster'));
  76. kerberosDescriptor.services.forEach(function (service) {
  77. var serviceName = service.name;
  78. // generate configs for service level identity objects
  79. configs = configs.concat(self.createResourceConfigs(service, serviceName));
  80. // generate configs for service component level identity object
  81. service.components.forEach(function (component) {
  82. configs = configs.concat(self.createResourceConfigs(component, serviceName));
  83. });
  84. });
  85. // unite cluster, service and component configs
  86. configs = configs.concat(clusterConfigs);
  87. self.processConfigReferences(kerberosDescriptor, configs);
  88. return configs;
  89. },
  90. /**
  91. *
  92. * @param {Object} resource
  93. * @param {String} serviceName
  94. * @return {Array}
  95. */
  96. createResourceConfigs: function (resource, serviceName) {
  97. var identityConfigs = [];
  98. var resourceConfigs = [];
  99. if (resource.identities) {
  100. identityConfigs = this.createConfigsByIdentities(resource.identities, serviceName);
  101. }
  102. if (resource.configurations) {
  103. resource.configurations.forEach(function (_configuration) {
  104. for (var key in _configuration) {
  105. resourceConfigs = resourceConfigs.concat(this.expandKerberosStackDescriptorProps(_configuration[key], serviceName, key));
  106. }
  107. }, this);
  108. }
  109. return identityConfigs.concat(resourceConfigs);
  110. },
  111. /**
  112. * Create service properties based on component identity
  113. *
  114. * @param {object[]} identities
  115. * @param {string} serviceName
  116. * @returns {App.ServiceConfigProperty[]}
  117. */
  118. createConfigsByIdentities: function (identities, serviceName) {
  119. var self = this;
  120. var configs = [];
  121. identities.forEach(function (identity) {
  122. var defaultObject = {
  123. isOverridable: false,
  124. isVisible: true,
  125. isSecureConfig: true,
  126. serviceName: serviceName,
  127. name: identity.name,
  128. identityType: identity.principal && identity.principal.type
  129. };
  130. self.parseIdentityObject(identity).forEach(function (item) {
  131. configs.push(App.ServiceConfigProperty.create($.extend({}, defaultObject, item)));
  132. });
  133. });
  134. return configs;
  135. },
  136. /**
  137. * Bootstrap base object according to identity info. Generate objects will be converted to
  138. * App.ServiceConfigProperty model class instances.
  139. *
  140. * @param {object} identity
  141. * @returns {object[]}
  142. */
  143. parseIdentityObject: function (identity) {
  144. var result = [];
  145. var name = identity.name;
  146. var self = this;
  147. Em.keys(identity).without('name').forEach(function (item) {
  148. var configObject = {};
  149. var prop = identity[item];
  150. var itemValue = prop[{keytab: 'file', principal: 'value'}[item]];
  151. var predefinedProperty;
  152. // skip inherited property without `configuration` and `keytab` or `file` values
  153. if (!prop.configuration && !itemValue) return;
  154. // inherited property with value should not observe value from reference
  155. if (name.startsWith('/') && !itemValue) {
  156. configObject.referenceProperty = name.substring(1) + ':' + item;
  157. configObject.isEditable = false;
  158. }
  159. configObject.defaultValue = configObject.savedValue = configObject.value = itemValue;
  160. configObject.filename = prop.configuration ? prop.configuration.split('/')[0] : 'cluster-env';
  161. configObject.name = prop.configuration ? prop.configuration.split('/')[1] : name + '_' + item;
  162. predefinedProperty = self.get('kerberosDescriptorProperties').findProperty('name', configObject.name);
  163. configObject.displayName = self._getDisplayNameForConfig(configObject.name, configObject.filename);
  164. configObject.index = predefinedProperty && !Em.isNone(predefinedProperty.index) ? predefinedProperty.index : Infinity;
  165. result.push(configObject);
  166. });
  167. return result;
  168. },
  169. /**
  170. * Get new config display name basing on its name and filename
  171. * If config <code>fileName</code> is `cluster-env`, normalizing for its <code>name</code> is used (@see App.format.normalizeName)
  172. * If config is predefined in the <code>secureProperties</code> (and it's displayName isn't empty there), predefined displayName is used
  173. * Otherwise - config <code>name</code> is returned
  174. *
  175. * @param {string} name config name
  176. * @param {string} fileName config filename
  177. * @returns {String} new config display name
  178. * @method _getDisplayNameForConfig
  179. * @private
  180. */
  181. _getDisplayNameForConfig: function(name, fileName) {
  182. return fileName == 'cluster-env' ? App.format.normalizeName(name) : name;
  183. },
  184. /**
  185. * Wrap kerberos properties to App.ServiceConfigProperty model class instances.
  186. *
  187. * @param {object} kerberosProperties
  188. * @param {string} serviceName
  189. * @param {string} filename
  190. * @returns {App.ServiceConfigProperty[]}
  191. */
  192. expandKerberosStackDescriptorProps: function (kerberosProperties, serviceName, filename) {
  193. var configs = [];
  194. for (var propertyName in kerberosProperties) {
  195. var predefinedProperty = this.get('kerberosDescriptorProperties').findProperty('name', propertyName);
  196. var propertyObject = {
  197. name: propertyName,
  198. value: kerberosProperties[propertyName],
  199. defaultValue: kerberosProperties[propertyName],
  200. savedValue: kerberosProperties[propertyName],
  201. serviceName: serviceName,
  202. filename: filename,
  203. displayName: serviceName == "Cluster" ? App.format.normalizeName(propertyName) : propertyName,
  204. isOverridable: false,
  205. isEditable: propertyName != 'realm',
  206. isRequired: propertyName != 'additional_realms',
  207. isSecureConfig: true,
  208. placeholderText: predefinedProperty && !Em.isNone(predefinedProperty.index) ? predefinedProperty.placeholderText : '',
  209. index: predefinedProperty && !Em.isNone(predefinedProperty.index) ? predefinedProperty.index : Infinity
  210. };
  211. configs.push(App.ServiceConfigProperty.create(propertyObject));
  212. }
  213. return configs;
  214. },
  215. /**
  216. * Take care about configs that should observe value from referenced configs.
  217. * Reference is set with `referenceProperty` key.
  218. *
  219. * @param {object[]} kerberosDescriptor
  220. * @param {App.ServiceConfigProperty[]} configs
  221. */
  222. processConfigReferences: function (kerberosDescriptor, configs) {
  223. var identities = kerberosDescriptor.identities;
  224. identities = identities.concat(kerberosDescriptor.services.map(function (service) {
  225. if (service.components && !!service.components.length) {
  226. identities = identities.concat(service.components.mapProperty('identities').reduce(function (p, c) {
  227. return p.concat(c);
  228. }, []));
  229. return identities;
  230. }
  231. }).reduce(function (p, c) {
  232. return p.concat(c);
  233. }, []));
  234. // clean up array
  235. identities = identities.compact().without(undefined);
  236. configs.forEach(function (item) {
  237. var reference = item.get('referenceProperty');
  238. if (!!reference) {
  239. var identity = identities.findProperty('name', reference.split(':')[0])[reference.split(':')[1]];
  240. if (identity && !!identity.configuration) {
  241. item.set('observesValueFrom', identity.configuration.split('/')[1]);
  242. } else {
  243. item.set('observesValueFrom', reference.replace(':', '_'));
  244. }
  245. }
  246. });
  247. },
  248. /**
  249. * update the kerberos descriptor to be put on cluster resource with user customizations
  250. * @param kerberosDescriptor {Object}
  251. * @param configs {Object}
  252. */
  253. updateKerberosDescriptor: function (kerberosDescriptor, configs) {
  254. configs.forEach(function (_config) {
  255. var isConfigUpdated;
  256. var isStackResouce = true;
  257. isConfigUpdated = this.updateResourceIdentityConfigs(kerberosDescriptor, _config, isStackResouce);
  258. if (!isConfigUpdated) {
  259. kerberosDescriptor.services.forEach(function (_service) {
  260. isConfigUpdated = this.updateResourceIdentityConfigs(_service, _config);
  261. if (!isConfigUpdated) {
  262. _service.components.forEach(function (_component) {
  263. isConfigUpdated = this.updateResourceIdentityConfigs(_component, _config);
  264. }, this);
  265. }
  266. }, this);
  267. }
  268. }, this);
  269. },
  270. /**
  271. * Updates the identity configs or configurations at a resource. A resource could be
  272. * 1) Stack
  273. * 2) Service
  274. * 3) Component
  275. * @param resource
  276. * @param config
  277. * @param isStackResource
  278. * @return boolean
  279. */
  280. updateResourceIdentityConfigs: function (resource, config, isStackResource) {
  281. var isConfigUpdated;
  282. var identities = resource.identities;
  283. var properties = !!isStackResource ? resource.properties : resource.configurations;
  284. isConfigUpdated = this.updateDescriptorConfigs(properties, config);
  285. if (!isConfigUpdated) {
  286. if (identities) {
  287. isConfigUpdated = this.updateDescriptorIdentityConfig(identities, config);
  288. }
  289. }
  290. return isConfigUpdated;
  291. },
  292. /**
  293. * This function updates stack/service/component level configurations of the kerberos descriptor
  294. * with the values entered by the user on the rendered ui
  295. * @param configurations
  296. * @param config
  297. * @return boolean
  298. */
  299. updateDescriptorConfigs: function (configurations, config) {
  300. var isConfigUpdated;
  301. if (!!configurations) {
  302. if (Array.isArray(configurations)) {
  303. configurations.forEach(function (_configuration) {
  304. for (var key in _configuration) {
  305. if (Object.keys(_configuration[key]).contains(config.name) && config.filename === key) {
  306. _configuration[key][config.name] = config.value;
  307. isConfigUpdated = true
  308. }
  309. }
  310. }, this);
  311. } else if (Object.keys(configurations).contains(config.name) && config.filename === 'stackConfigs') {
  312. configurations[config.name] = config.value;
  313. isConfigUpdated = true;
  314. }
  315. }
  316. return isConfigUpdated;
  317. },
  318. /**
  319. * This function updates stack/service/component level kerberos descriptor identities (principal and keytab)
  320. * with the values entered by the user on the rendered ui
  321. * @param identities
  322. * @param config
  323. * @return boolean
  324. */
  325. updateDescriptorIdentityConfig: function (identities, config) {
  326. var isConfigUpdated = false;
  327. identities.forEach(function (identity) {
  328. var keys = Em.keys(identity).without('name');
  329. keys.forEach(function (item) {
  330. var prop = identity[item];
  331. // compare ui rendered config against identity with `configuration attribute` (Most of the identities have `configuration attribute`)
  332. var isIdentityWithConfig = (prop.configuration && prop.configuration.split('/')[0] === config.filename && prop.configuration.split('/')[1] === config.name);
  333. // compare ui rendered config against identity without `configuration attribute` (For example spnego principal and keytab)
  334. var isIdentityWithoutConfig = (!prop.configuration && identity.name === config.name.split('_')[0] && item === config.name.split('_')[1]);
  335. if (isIdentityWithConfig || isIdentityWithoutConfig) {
  336. prop[{keytab: 'file', principal: 'value'}[item]] = config.value;
  337. isConfigUpdated = true;
  338. }
  339. });
  340. }, this);
  341. return isConfigUpdated;
  342. },
  343. /**
  344. * Make request for stack descriptor configs if cluster is not secure
  345. * or cluster descriptor configs if cluster is secure
  346. * @returns {$.ajax}
  347. * @method loadStackDescriptorConfigs
  348. */
  349. loadDescriptorConfigs: function() {
  350. if (this.get('shouldLoadClusterDescriptor')) {
  351. return this.loadClusterDescriptorConfigs();
  352. } else {
  353. return this.loadStackDescriptorConfigs();
  354. }
  355. },
  356. /**
  357. * Check if cluster descriptor should be loaded
  358. * @returns {Boolean}
  359. */
  360. shouldLoadClusterDescriptor: function() {
  361. return App.get('isKerberosEnabled') && !App.router.get('mainAdminKerberosController.defaultKerberosLoaded');
  362. }.property('App.isKerberosEnabled', 'App.router.mainAdminKerberosController.defaultKerberosLoaded'),
  363. /**
  364. * Make request for stack descriptor configs.
  365. * @returns {$.ajax}
  366. * @method loadStackDescriptorConfigs
  367. */
  368. loadStackDescriptorConfigs: function () {
  369. return App.ajax.send({
  370. sender: this,
  371. name: 'admin.kerberize.stack_descriptor',
  372. data: {
  373. stackName: App.get('currentStackName'),
  374. stackVersionNumber: App.get('currentStackVersionNumber')
  375. }
  376. });
  377. },
  378. /**
  379. * Make request for cluster descriptor configs.
  380. * @returns {$.ajax}
  381. * @method loadClusterDescriptorConfigs
  382. */
  383. loadClusterDescriptorConfigs: function () {
  384. return App.ajax.send({
  385. sender: this,
  386. name: 'admin.kerberize.cluster_descriptor'
  387. });
  388. }
  389. });