addSecurityConfigs.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  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. /**
  20. * Mixin for loading and setting secure configs
  21. *
  22. * @type {Ember.Mixin}
  23. */
  24. App.AddSecurityConfigs = Em.Mixin.create({
  25. kerberosDescriptor: {},
  26. kerberosDescriptorProperties: require('data/HDP2/kerberos_descriptor_properties'),
  27. /**
  28. * security configs, which values should be modified after APPLY CONFIGURATIONS stage
  29. */
  30. secureConfigs: [
  31. {
  32. name: 'zookeeper_principal_name',
  33. serviceName: 'ZOOKEEPER'
  34. },
  35. {
  36. name: 'knox_principal_name',
  37. serviceName: 'KNOX'
  38. },
  39. {
  40. name: 'storm_principal_name',
  41. serviceName: 'STORM'
  42. },
  43. {
  44. name: 'nimbus_principal_name',
  45. serviceName: 'STORM'
  46. }
  47. ],
  48. /**
  49. * Store status of kerberos descriptor located in cluster artifacts.
  50. * This status needed for Add Service Wizard to select appropriate method to create
  51. * or update descriptor.
  52. *
  53. * @param {Boolean} isExists <code>true</code> if cluster descriptor present
  54. */
  55. storeClusterDescriptorStatus: function(isExists) {
  56. if (this.get('isWithinAddService')) {
  57. this.get('wizardController').setDBProperty('isClusterDescriptorExists', isExists);
  58. }
  59. },
  60. /**
  61. *
  62. * @param {object[]} items - stack descriptor json response
  63. * @returns {App.ServiceConfigProperty[]}
  64. */
  65. createServicesStackDescriptorConfigs: function (items) {
  66. var self = this;
  67. var configs = [];
  68. var clusterConfigs = [];
  69. var kerberosDescriptor = Em.get(items, 'KerberosDescriptor.kerberos_descriptor');
  70. this.set('kerberosDescriptor', kerberosDescriptor);
  71. // generate configs for root level properties object, currently realm, keytab_dir
  72. clusterConfigs = clusterConfigs.concat(this.expandKerberosStackDescriptorProps(kerberosDescriptor.properties, 'Cluster', 'stackConfigs'));
  73. // generate configs for root level identities object, currently spnego property
  74. clusterConfigs = clusterConfigs.concat(this.createConfigsByIdentities(kerberosDescriptor.identities, 'Cluster'));
  75. kerberosDescriptor.services.forEach(function (service) {
  76. var serviceName = service.name;
  77. // generate configs for service level identity objects
  78. configs = configs.concat(self.createResourceConfigs(service, serviceName));
  79. // generate configs for service component level identity object
  80. service.components.forEach(function (component) {
  81. configs = configs.concat(self.createResourceConfigs(component, serviceName));
  82. });
  83. });
  84. // unite cluster, service and component configs
  85. configs = configs.concat(clusterConfigs);
  86. self.processConfigReferences(kerberosDescriptor, configs);
  87. return configs;
  88. },
  89. /**
  90. *
  91. * @param {Object} resource
  92. * @param {String} serviceName
  93. * @return {Array}
  94. */
  95. createResourceConfigs: function (resource, serviceName) {
  96. var identityConfigs = [];
  97. var resourceConfigs = [];
  98. if (resource.identities) {
  99. identityConfigs = this.createConfigsByIdentities(resource.identities, serviceName);
  100. }
  101. if (resource.configurations) {
  102. resource.configurations.forEach(function (_configuration) {
  103. for (var key in _configuration) {
  104. resourceConfigs = resourceConfigs.concat(this.expandKerberosStackDescriptorProps(_configuration[key], serviceName, key));
  105. }
  106. }, this);
  107. }
  108. return identityConfigs.concat(resourceConfigs);
  109. },
  110. /**
  111. * Create service properties based on component identity
  112. *
  113. * @param {object[]} identities
  114. * @param {string} serviceName
  115. * @returns {App.ServiceConfigProperty[]}
  116. */
  117. createConfigsByIdentities: function (identities, serviceName) {
  118. var self = this;
  119. var configs = [];
  120. identities.forEach(function (identity) {
  121. var defaultObject = {
  122. isConfigIdentity: true,
  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. Em.setProperties(configObject, {
  160. recommendedValue: itemValue,
  161. initialValue: itemValue,
  162. defaultValue: itemValue,
  163. value: itemValue
  164. });
  165. configObject.filename = prop.configuration ? prop.configuration.split('/')[0] : 'cluster-env';
  166. configObject.name = prop.configuration ? prop.configuration.split('/')[1] : name + '_' + item;
  167. predefinedProperty = self.get('kerberosDescriptorProperties').findProperty('name', configObject.name);
  168. configObject.displayName = self._getDisplayNameForConfig(configObject.name, configObject.filename);
  169. configObject.index = predefinedProperty && !Em.isNone(predefinedProperty.index) ? predefinedProperty.index : Infinity;
  170. result.push(configObject);
  171. });
  172. return result;
  173. },
  174. /**
  175. * Get new config display name basing on its name and filename
  176. * If config <code>fileName</code> is `cluster-env`, normalizing for its <code>name</code> is used (@see App.format.normalizeName)
  177. * If config is predefined in the <code>secureProperties</code> (and it's displayName isn't empty there), predefined displayName is used
  178. * Otherwise - config <code>name</code> is returned
  179. *
  180. * @param {string} name config name
  181. * @param {string} fileName config filename
  182. * @returns {String} new config display name
  183. * @method _getDisplayNameForConfig
  184. * @private
  185. */
  186. _getDisplayNameForConfig: function (name, fileName) {
  187. var predefinedConfig = App.config.get('kerberosIdentitiesMap')[App.config.configId(name, fileName)];
  188. return (predefinedConfig && predefinedConfig.displayName)
  189. ? predefinedConfig.displayName
  190. : fileName == 'cluster-env' ? App.format.normalizeName(name) : name;
  191. },
  192. /**
  193. * Wrap kerberos properties to App.ServiceConfigProperty model class instances.
  194. *
  195. * @param {object} kerberosProperties
  196. * @param {string} serviceName
  197. * @param {string} filename
  198. * @returns {App.ServiceConfigProperty[]}
  199. */
  200. expandKerberosStackDescriptorProps: function (kerberosProperties, serviceName, filename) {
  201. var configs = [];
  202. for (var propertyName in kerberosProperties) {
  203. var predefinedProperty = this.get('kerberosDescriptorProperties').findProperty('name', propertyName);
  204. var value = kerberosProperties[propertyName];
  205. var isRequired = propertyName == 'additional_realms' ? false : value !== "";
  206. var propertyObject = {
  207. name: propertyName,
  208. value: value,
  209. defaultValue: value,
  210. recommendedValue: value,
  211. initialValue: value,
  212. serviceName: serviceName,
  213. filename: filename,
  214. displayName: serviceName == "Cluster" ? App.format.normalizeName(propertyName) : propertyName,
  215. isOverridable: false,
  216. isEditable: propertyName != 'realm',
  217. isRequired: isRequired,
  218. isSecureConfig: true,
  219. placeholderText: predefinedProperty && !Em.isNone(predefinedProperty.index) ? predefinedProperty.placeholderText : '',
  220. index: predefinedProperty && !Em.isNone(predefinedProperty.index) ? predefinedProperty.index : Infinity
  221. };
  222. configs.push(App.ServiceConfigProperty.create(propertyObject));
  223. }
  224. return configs;
  225. },
  226. /**
  227. * Take care about configs that should observe value from referenced configs.
  228. * Reference is set with `referenceProperty` key.
  229. *
  230. * @param {object[]} kerberosDescriptor
  231. * @param {App.ServiceConfigProperty[]} configs
  232. */
  233. processConfigReferences: function (kerberosDescriptor, configs) {
  234. var identities = kerberosDescriptor.identities;
  235. /**
  236. * Returns indentity object with additional attribute `referencePath`.
  237. * Reference path depends on how deep identity is. Each level separated by `/` sign.
  238. *
  239. * @param {object} identity
  240. * @param {string} [prefix=false] prefix to append e.g. 'SERVICE_NAME'
  241. * @returns {object} identity object
  242. */
  243. var setReferencePath = function(identity, prefix) {
  244. var name = Em.getWithDefault(identity, 'name', false);
  245. if (name) {
  246. if (prefix) {
  247. name = prefix + '/' + name;
  248. }
  249. identity.referencePath = name;
  250. }
  251. return identity;
  252. };
  253. // map all identities and add attribute `referencePath`
  254. // `referencePath` is a path to identity it can be 1-3 levels
  255. // 1 for "/global" identity e.g. `/spnego`
  256. // 2 for "/SERVICE/identity"
  257. // 3 for "/SERVICE/COMPONENT/identity"
  258. identities = identities.map(function(i) {
  259. return setReferencePath(i);
  260. })
  261. .concat(kerberosDescriptor.services.map(function (service) {
  262. var serviceName = Em.getWithDefault(service, 'name', false);
  263. var serviceIdentities = Em.getWithDefault(service, 'identities', []).map(function(i) {
  264. return setReferencePath(i, serviceName);
  265. });
  266. var componentIdentities = Em.getWithDefault(service || {}, 'components', []).map(function(i) {
  267. var componentName = Em.getWithDefault(i, 'name', false);
  268. return Em.getWithDefault(i, 'identities', []).map(function(componentIdentity) {
  269. return setReferencePath(componentIdentity, serviceName + '/' + componentName);
  270. });
  271. }).reduce(function(p, c) {
  272. return p.concat(c);
  273. }, []);
  274. serviceIdentities.pushObjects(componentIdentities);
  275. return serviceIdentities;
  276. }).reduce(function (p, c) {
  277. return p.concat(c);
  278. }, []));
  279. // clean up array
  280. identities = identities.compact().without(undefined);
  281. configs.forEach(function (item) {
  282. var reference = item.get('referenceProperty');
  283. if (!!reference) {
  284. // first find identity by `name`
  285. // if not found try to find by `referencePath`
  286. var identity = Em.getWithDefault(identities.findProperty('name', reference.split(':')[0]) || {}, reference.split(':')[1], false) ||
  287. Em.getWithDefault(identities.findProperty('referencePath', reference.split(':')[0]) || {}, reference.split(':')[1], false);
  288. if (identity && !!identity.configuration) {
  289. item.set('observesValueFrom', identity.configuration.split('/')[1]);
  290. } else {
  291. item.set('observesValueFrom', reference.replace(':', '_'));
  292. }
  293. }
  294. });
  295. },
  296. /**
  297. * update the kerberos descriptor to be put on cluster resource with user customizations
  298. * @param kerberosDescriptor {Object}
  299. * @param configs {Object}
  300. */
  301. updateKerberosDescriptor: function (kerberosDescriptor, configs) {
  302. configs.forEach(function (_config) {
  303. var isConfigUpdated;
  304. var isStackResouce = true;
  305. isConfigUpdated = this.updateResourceIdentityConfigs(kerberosDescriptor, _config, isStackResouce);
  306. if (!isConfigUpdated) {
  307. kerberosDescriptor.services.forEach(function (_service) {
  308. isConfigUpdated = this.updateResourceIdentityConfigs(_service, _config);
  309. if (!isConfigUpdated) {
  310. _service.components.forEach(function (_component) {
  311. isConfigUpdated = this.updateResourceIdentityConfigs(_component, _config);
  312. }, this);
  313. }
  314. }, this);
  315. }
  316. }, this);
  317. },
  318. /**
  319. * Updates the identity configs or configurations at a resource. A resource could be
  320. * 1) Stack
  321. * 2) Service
  322. * 3) Component
  323. * @param resource
  324. * @param config
  325. * @param isStackResource
  326. * @return boolean
  327. */
  328. updateResourceIdentityConfigs: function (resource, config, isStackResource) {
  329. var isConfigUpdated;
  330. var identities = resource.identities;
  331. var properties = !!isStackResource ? resource.properties : resource.configurations;
  332. isConfigUpdated = this.updateDescriptorConfigs(properties, config);
  333. if (!isConfigUpdated) {
  334. if (identities) {
  335. isConfigUpdated = this.updateDescriptorIdentityConfig(identities, config);
  336. }
  337. }
  338. return isConfigUpdated;
  339. },
  340. /**
  341. * This function updates stack/service/component level configurations of the kerberos descriptor
  342. * with the values entered by the user on the rendered ui
  343. * @param configurations
  344. * @param config
  345. * @return boolean
  346. */
  347. updateDescriptorConfigs: function (configurations, config) {
  348. var isConfigUpdated;
  349. if (!!configurations) {
  350. if (Array.isArray(configurations)) {
  351. configurations.forEach(function (_configuration) {
  352. for (var key in _configuration) {
  353. if (Object.keys(_configuration[key]).contains(config.name) && config.filename === key) {
  354. _configuration[key][config.name] = config.value;
  355. isConfigUpdated = true
  356. }
  357. }
  358. }, this);
  359. } else if (Object.keys(configurations).contains(config.name) && config.filename === 'stackConfigs') {
  360. configurations[config.name] = config.value;
  361. isConfigUpdated = true;
  362. }
  363. }
  364. return isConfigUpdated;
  365. },
  366. /**
  367. * This function updates stack/service/component level kerberos descriptor identities (principal and keytab)
  368. * with the values entered by the user on the rendered ui
  369. * @param identities
  370. * @param config
  371. * @return boolean
  372. */
  373. updateDescriptorIdentityConfig: function (identities, config) {
  374. var isConfigUpdated = false;
  375. identities.forEach(function (identity) {
  376. var keys = Em.keys(identity).without('name');
  377. keys.forEach(function (item) {
  378. var prop = identity[item];
  379. // compare ui rendered config against identity with `configuration attribute` (Most of the identities have `configuration attribute`)
  380. var isIdentityWithConfig = (prop.configuration && prop.configuration.split('/')[0] === config.filename && prop.configuration.split('/')[1] === config.name);
  381. // compare ui rendered config against identity without `configuration attribute` (For example spnego principal and keytab)
  382. var isIdentityWithoutConfig = (!prop.configuration && identity.name === config.name.split('_')[0] && item === config.name.split('_')[1]);
  383. if (isIdentityWithConfig || isIdentityWithoutConfig) {
  384. prop[{keytab: 'file', principal: 'value'}[item]] = config.value;
  385. isConfigUpdated = true;
  386. }
  387. });
  388. }, this);
  389. return isConfigUpdated;
  390. },
  391. /**
  392. * Check if cluster descriptor should be loaded
  393. * @returns {Boolean}
  394. */
  395. shouldLoadClusterDescriptor: function() {
  396. return App.get('isKerberosEnabled') && !App.router.get('mainAdminKerberosController.defaultKerberosLoaded');
  397. }.property('App.isKerberosEnabled', 'App.router.mainAdminKerberosController.defaultKerberosLoaded'),
  398. /**
  399. * Make request for stack descriptor configs.
  400. * @returns {$.ajax}
  401. * @method loadStackDescriptorConfigs
  402. */
  403. loadStackDescriptorConfigs: function () {
  404. return App.ajax.send({
  405. sender: this,
  406. name: 'admin.kerberize.stack_descriptor',
  407. data: {
  408. stackName: App.get('currentStackName'),
  409. stackVersionNumber: App.get('currentStackVersionNumber')
  410. }
  411. });
  412. },
  413. /**
  414. * Make request for cluster descriptor configs.
  415. * @returns {$.ajax}
  416. * @method loadClusterDescriptorConfigs
  417. */
  418. loadClusterDescriptorConfigs: function () {
  419. return App.ajax.send({
  420. sender: this,
  421. name: 'admin.kerberize.cluster_descriptor'
  422. });
  423. }
  424. });