addSecurityConfigs.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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. /**
  27. * security configs, which values should be modified after APPLY CONFIGURATIONS stage
  28. */
  29. secureConfigs: function () {
  30. var configs = [
  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. if (App.get('isHadoop22Stack')) {
  45. configs.push({
  46. name: 'nimbus_principal_name',
  47. serviceName: 'STORM'
  48. });
  49. }
  50. return configs;
  51. }.property('App.isHadoop22Stack'),
  52. /**
  53. * Generate stack descriptor configs.
  54. *
  55. * @returns {$.Deferred}
  56. */
  57. getDescriptorConfigs: function () {
  58. return this.loadDescriptorConfigs().pipe(this.createServicesStackDescriptorConfigs.bind(this));
  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 = items.artifact_data;
  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. isOverridable: false,
  123. isVisible: true,
  124. isSecureConfig: true,
  125. serviceName: serviceName,
  126. name: identity.name,
  127. identityType: identity.principal && identity.principal.type
  128. };
  129. self.parseIdentityObject(identity).forEach(function (item) {
  130. configs.push(App.ServiceConfigProperty.create($.extend({}, defaultObject, item)));
  131. });
  132. });
  133. return configs;
  134. },
  135. /**
  136. * Bootstrap base object according to identity info. Generate objects will be converted to
  137. * App.ServiceConfigProperty model class instances.
  138. *
  139. * @param {object} identity
  140. * @returns {object[]}
  141. */
  142. parseIdentityObject: function (identity) {
  143. var result = [];
  144. var name = identity.name;
  145. var keys = Em.keys(identity).without('name');
  146. keys.forEach(function (item) {
  147. var configObject = {};
  148. var prop = identity[item];
  149. var itemValue = prop[{keytab: 'file', principal: 'value'}[item]];
  150. // skip inherited property without `configuration` and `keytab` or `file` values
  151. if (!prop.configuration && !itemValue) return;
  152. // inherited property with value should not observe value from reference
  153. if (name.startsWith('/') && !itemValue) {
  154. configObject.referenceProperty = name.substring(1) + ':' + item;
  155. configObject.isEditable = false;
  156. }
  157. configObject.defaultValue = configObject.savedValue = configObject.value = itemValue;
  158. configObject.filename = prop.configuration ? prop.configuration.split('/')[0] : 'cluster-env';
  159. configObject.name = prop.configuration ? prop.configuration.split('/')[1] : name + '_' + item;
  160. configObject.displayName = configObject.filename == "cluster-env" ? App.format.normalizeName(configObject.name) : configObject.name;
  161. result.push(configObject);
  162. });
  163. return result;
  164. },
  165. /**
  166. * Wrap kerberos properties to App.ServiceConfigProperty model class instances.
  167. *
  168. * @param {object} kerberosProperties
  169. * @param {string} serviceName
  170. * @param {string} filename
  171. * @returns {App.ServiceConfigProperty[]}
  172. */
  173. expandKerberosStackDescriptorProps: function (kerberosProperties, serviceName, filename) {
  174. var configs = [];
  175. for (var propertyName in kerberosProperties) {
  176. var propertyObject = {
  177. name: propertyName,
  178. value: kerberosProperties[propertyName],
  179. defaultValue: kerberosProperties[propertyName],
  180. savedValue: kerberosProperties[propertyName],
  181. serviceName: serviceName,
  182. filename: filename,
  183. displayName: serviceName == "Cluster" ? App.format.normalizeName(propertyName) : propertyName,
  184. isOverridable: false,
  185. isEditable: propertyName != 'realm',
  186. isSecureConfig: true
  187. };
  188. configs.push(App.ServiceConfigProperty.create(propertyObject));
  189. }
  190. return configs;
  191. },
  192. /**
  193. * Take care about configs that should observe value from referenced configs.
  194. * Reference is set with `referenceProperty` key.
  195. *
  196. * @param {object[]} kerberosDescriptor
  197. * @param {App.ServiceConfigProperty[]} configs
  198. */
  199. processConfigReferences: function (kerberosDescriptor, configs) {
  200. var identities = kerberosDescriptor.identities;
  201. identities = identities.concat(kerberosDescriptor.services.map(function (service) {
  202. var _identities = service.identities || [];
  203. if (service.components && !!service.components.length) {
  204. identities = identities.concat(service.components.mapProperty('identities').reduce(function (p, c) {
  205. return p.concat(c);
  206. }, []));
  207. return identities;
  208. }
  209. }).reduce(function (p, c) {
  210. return p.concat(c);
  211. }, []));
  212. // clean up array
  213. identities = identities.compact().without(undefined);
  214. configs.forEach(function (item) {
  215. var reference = item.get('referenceProperty');
  216. if (!!reference) {
  217. var identity = identities.findProperty('name', reference.split(':')[0])[reference.split(':')[1]];
  218. if (identity && !!identity.configuration) {
  219. item.set('observesValueFrom', identity.configuration.split('/')[1]);
  220. } else {
  221. item.set('observesValueFrom', reference.replace(':', '_'));
  222. }
  223. }
  224. });
  225. },
  226. /**
  227. * update the kerberos descriptor to be put on cluster resource with user customizations
  228. * @param kerberosDescriptor {Object}
  229. * @param configs {Object}
  230. */
  231. updateKerberosDescriptor: function (kerberosDescriptor, configs) {
  232. configs.forEach(function (_config) {
  233. var isConfigUpdated;
  234. var isStackResouce = true;
  235. isConfigUpdated = this.updateResourceIdentityConfigs(kerberosDescriptor, _config, isStackResouce);
  236. if (!isConfigUpdated) {
  237. kerberosDescriptor.services.forEach(function (_service) {
  238. isConfigUpdated = this.updateResourceIdentityConfigs(_service, _config);
  239. if (!isConfigUpdated) {
  240. _service.components.forEach(function (_component) {
  241. isConfigUpdated = this.updateResourceIdentityConfigs(_component, _config);
  242. }, this);
  243. }
  244. }, this);
  245. }
  246. }, this);
  247. },
  248. /**
  249. * Updates the identity configs or configurations at a resource. A resource could be
  250. * 1) Stack
  251. * 2) Service
  252. * 3) Component
  253. * @param resource
  254. * @param config
  255. * @param isStackResource
  256. * @return boolean
  257. */
  258. updateResourceIdentityConfigs: function (resource, config, isStackResource) {
  259. var isConfigUpdated;
  260. var identities = resource.identities;
  261. var properties = !!isStackResource ? resource.properties : resource.configurations;
  262. isConfigUpdated = this.updateDescriptorConfigs(properties, config);
  263. if (!isConfigUpdated) {
  264. if (identities) {
  265. isConfigUpdated = this.updateDescriptorIdentityConfig(identities, config);
  266. }
  267. }
  268. return isConfigUpdated;
  269. },
  270. /**
  271. * This function updates stack/service/component level configurations of the kerberos descriptor
  272. * with the values entered by the user on the rendered ui
  273. * @param configurations
  274. * @param config
  275. * @return boolean
  276. */
  277. updateDescriptorConfigs: function (configurations, config) {
  278. var isConfigUpdated;
  279. if (!!configurations) {
  280. if (Array.isArray(configurations)) {
  281. configurations.forEach(function (_configuration) {
  282. for (var key in _configuration) {
  283. if (Object.keys(_configuration[key]).contains(config.name) && config.filename === key) {
  284. _configuration[key][config.name] = config.value;
  285. isConfigUpdated = true
  286. }
  287. }
  288. }, this);
  289. } else if (Object.keys(configurations).contains(config.name) && config.filename === 'stackConfigs') {
  290. configurations[config.name] = config.value;
  291. isConfigUpdated = true
  292. }
  293. }
  294. return isConfigUpdated;
  295. },
  296. /**
  297. * This function updates stack/service/component level kerberos descriptor identities (principal and keytab)
  298. * with the values entered by the user on the rendered ui
  299. * @param identities
  300. * @param config
  301. * @return boolean
  302. */
  303. updateDescriptorIdentityConfig: function (identities, config) {
  304. var isConfigUpdated = false;
  305. identities.forEach(function (identity) {
  306. var keys = Em.keys(identity).without('name');
  307. keys.forEach(function (item) {
  308. var prop = identity[item];
  309. // compare ui rendered config against identity with `configuration attribute` (Most of the identities have `configuration attribute`)
  310. var isIdentityWithConfig = (prop.configuration && prop.configuration.split('/')[0] === config.filename && prop.configuration.split('/')[1] === config.name);
  311. // compare ui rendered config against identity without `configuration attribute` (For example spnego principal and keytab)
  312. var isIdentityWithoutConfig = (!prop.configuration && identity.name === config.name.split('_')[0] && item === config.name.split('_')[1]);
  313. if (isIdentityWithConfig || isIdentityWithoutConfig) {
  314. prop[{keytab: 'file', principal: 'value'}[item]] = config.value;
  315. isConfigUpdated = true;
  316. }
  317. });
  318. }, this);
  319. return isConfigUpdated;
  320. },
  321. /**
  322. * Make request for stack descriptor configs if cluster is not secure
  323. * or cluster descriptor configs if cluster is secure
  324. * @returns {$.ajax}
  325. * @method loadStackDescriptorConfigs
  326. */
  327. loadDescriptorConfigs: function() {
  328. if (this.get('shouldLoadClusterDescriptor')) {
  329. return this.loadClusterDescriptorConfigs();
  330. } else {
  331. return this.loadStackDescriptorConfigs();
  332. }
  333. },
  334. /**
  335. * Check if cluster descriptor should be loaded
  336. * @returns {Boolean}
  337. */
  338. shouldLoadClusterDescriptor: function() {
  339. return App.get('isKerberosEnabled') && !App.router.get('mainAdminKerberosController.defaultKerberosLoaded');
  340. }.property('App.router.mainAdminKerberosController.securityEnabled', 'App.router.mainAdminKerberosController.defaultKerberosLoaded'),
  341. /**
  342. * Make request for stack descriptor configs.
  343. * @returns {$.ajax}
  344. * @method loadStackDescriptorConfigs
  345. */
  346. loadStackDescriptorConfigs: function () {
  347. return App.ajax.send({
  348. sender: this,
  349. name: 'admin.kerberize.stack_descriptor',
  350. data: {
  351. stackName: App.get('currentStackName'),
  352. stackVersionNumber: App.get('currentStackVersionNumber')
  353. }
  354. });
  355. },
  356. /**
  357. * Make request for cluster descriptor configs.
  358. * @returns {$.ajax}
  359. * @method loadClusterDescriptorConfigs
  360. */
  361. loadClusterDescriptorConfigs: function () {
  362. return App.ajax.send({
  363. sender: this,
  364. name: 'admin.kerberize.cluster_descriptor'
  365. });
  366. }
  367. });