chef 12.0.0.alpha.0 → 12.0.0.alpha.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (207) hide show
  1. checksums.yaml +4 -4
  2. data/CONTRIBUTING.md +3 -5
  3. data/lib/chef/api_client.rb +1 -1
  4. data/lib/chef/application.rb +16 -8
  5. data/lib/chef/chef_fs/chef_fs_data_store.rb +1 -1
  6. data/lib/chef/chef_fs/command_line.rb +1 -1
  7. data/lib/chef/chef_fs/file_system.rb +1 -1
  8. data/lib/chef/chef_fs/file_system/acl_entry.rb +1 -1
  9. data/lib/chef/chef_fs/file_system/chef_repository_file_system_entry.rb +3 -3
  10. data/lib/chef/chef_fs/file_system/cookbook_file.rb +2 -2
  11. data/lib/chef/chef_fs/file_system/rest_list_dir.rb +2 -2
  12. data/lib/chef/chef_fs/file_system/rest_list_entry.rb +4 -4
  13. data/lib/chef/config.rb +6 -5
  14. data/lib/chef/config_fetcher.rb +1 -1
  15. data/lib/chef/cookbook/cookbook_version_loader.rb +126 -43
  16. data/lib/chef/cookbook/metadata.rb +102 -53
  17. data/lib/chef/cookbook/syntax_check.rb +1 -1
  18. data/lib/chef/cookbook_loader.rb +62 -14
  19. data/lib/chef/cookbook_site_streaming_uploader.rb +12 -1
  20. data/lib/chef/cookbook_version.rb +13 -4
  21. data/lib/chef/data_bag.rb +28 -15
  22. data/lib/chef/data_bag_item.rb +5 -7
  23. data/lib/chef/digester.rb +5 -9
  24. data/lib/chef/dsl/recipe.rb +14 -0
  25. data/lib/chef/encrypted_data_bag_item.rb +1 -0
  26. data/lib/chef/encrypted_data_bag_item/assertions.rb +57 -0
  27. data/lib/chef/encrypted_data_bag_item/decryptor.rb +52 -28
  28. data/lib/chef/encrypted_data_bag_item/encrypted_data_bag_item_assertions.rb +37 -0
  29. data/lib/chef/encrypted_data_bag_item/encryption_failure.rb +22 -0
  30. data/lib/chef/encrypted_data_bag_item/encryptor.rb +79 -8
  31. data/lib/chef/environment.rb +1 -3
  32. data/lib/chef/exceptions.rb +18 -3
  33. data/lib/chef/formatters/base.rb +7 -0
  34. data/lib/chef/formatters/error_inspectors/cookbook_resolve_error_inspector.rb +1 -1
  35. data/lib/chef/handler/json_file.rb +0 -1
  36. data/lib/chef/http/json_output.rb +1 -1
  37. data/lib/chef/json_compat.rb +24 -6
  38. data/lib/chef/knife/bootstrap.rb +2 -2
  39. data/lib/chef/knife/client_delete.rb +1 -1
  40. data/lib/chef/knife/cookbook_site_download.rb +1 -1
  41. data/lib/chef/knife/cookbook_site_list.rb +1 -1
  42. data/lib/chef/knife/cookbook_site_search.rb +1 -1
  43. data/lib/chef/knife/cookbook_site_share.rb +2 -2
  44. data/lib/chef/knife/cookbook_site_show.rb +3 -3
  45. data/lib/chef/knife/cookbook_site_unshare.rb +1 -1
  46. data/lib/chef/knife/core/node_editor.rb +2 -3
  47. data/lib/chef/knife/core/ui.rb +2 -2
  48. data/lib/chef/knife/deps.rb +2 -3
  49. data/lib/chef/mixin/shell_out.rb +1 -1
  50. data/lib/chef/mixin/windows_architecture_helper.rb +1 -0
  51. data/lib/chef/node.rb +1 -2
  52. data/lib/chef/platform/provider_mapping.rb +33 -6
  53. data/lib/chef/provider.rb +0 -2
  54. data/lib/chef/provider/cookbook_file/content.rb +1 -1
  55. data/lib/chef/provider/cron.rb +11 -0
  56. data/lib/chef/provider/deploy.rb +3 -2
  57. data/lib/chef/provider/deploy/revision.rb +2 -2
  58. data/lib/chef/provider/env.rb +1 -1
  59. data/lib/chef/provider/env/windows.rb +5 -9
  60. data/lib/chef/provider/file.rb +84 -33
  61. data/lib/chef/provider/git.rb +2 -1
  62. data/lib/chef/provider/group/aix.rb +17 -2
  63. data/lib/chef/provider/group/dscl.rb +27 -9
  64. data/lib/chef/provider/group/pw.rb +8 -1
  65. data/lib/chef/provider/http_request.rb +4 -4
  66. data/lib/chef/provider/log.rb +4 -14
  67. data/lib/chef/provider/mount/mount.rb +2 -2
  68. data/lib/chef/provider/package/ips.rb +17 -23
  69. data/lib/chef/provider/package/paludis.rb +2 -2
  70. data/lib/chef/provider/package/rpm.rb +2 -2
  71. data/lib/chef/provider/package/rubygems.rb +2 -0
  72. data/lib/chef/provider/package/yum.rb +2 -0
  73. data/lib/chef/provider/package/zypper.rb +1 -1
  74. data/lib/chef/provider/remote_file/cache_control_data.rb +2 -2
  75. data/lib/chef/provider/service/windows.rb +87 -21
  76. data/lib/chef/provider/user/aix.rb +95 -0
  77. data/lib/chef/provider/user/dscl.rb +544 -156
  78. data/lib/chef/provider/user/useradd.rb +1 -0
  79. data/lib/chef/providers.rb +1 -0
  80. data/lib/chef/resource.rb +4 -3
  81. data/lib/chef/resource/freebsd_package.rb +10 -2
  82. data/lib/chef/resource/paludis_package.rb +1 -0
  83. data/lib/chef/resource/scm.rb +10 -0
  84. data/lib/chef/resource/user.rb +27 -0
  85. data/lib/chef/resource/windows_service.rb +53 -0
  86. data/lib/chef/resource_collection.rb +23 -12
  87. data/lib/chef/resource_reporter.rb +10 -10
  88. data/lib/chef/resources.rb +1 -0
  89. data/lib/chef/role.rb +3 -3
  90. data/lib/chef/run_list.rb +6 -3
  91. data/lib/chef/user.rb +1 -1
  92. data/lib/chef/util/diff.rb +1 -2
  93. data/lib/chef/version.rb +1 -1
  94. data/lib/chef/version_constraint.rb +4 -4
  95. data/spec/data/cookbooks/angrybash/metadata.rb +2 -0
  96. data/spec/data/cookbooks/apache2/metadata.rb +2 -0
  97. data/spec/data/cookbooks/borken/metadata.rb +2 -0
  98. data/spec/data/cookbooks/ignorken/metadata.rb +2 -0
  99. data/spec/data/cookbooks/java/metadata.rb +2 -0
  100. data/spec/data/cookbooks/name-mismatch-versionnumber/README.md +4 -0
  101. data/spec/data/cookbooks/name-mismatch-versionnumber/metadata.rb +8 -0
  102. data/spec/data/cookbooks/name-mismatch-versionnumber/recipes/default.rb +8 -0
  103. data/spec/data/cookbooks/openldap/files/default/remotedir/not_a_template.erb +2 -0
  104. data/spec/data/cookbooks/preseed/metadata.rb +2 -0
  105. data/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/README.md +4 -0
  106. data/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/metadata.rb +13 -0
  107. data/spec/data/incomplete-metadata-chef-repo/incomplete-metadata/recipes/default.rb +8 -0
  108. data/spec/data/invalid-metadata-chef-repo/invalid-metadata/README.md +4 -0
  109. data/spec/data/invalid-metadata-chef-repo/invalid-metadata/metadata.rb +10 -0
  110. data/spec/data/invalid-metadata-chef-repo/invalid-metadata/recipes/default.rb +8 -0
  111. data/spec/data/mac_users/10.7-8.plist.xml +559 -0
  112. data/spec/data/mac_users/10.7-8.shadow.xml +11 -0
  113. data/spec/data/mac_users/10.7.plist.xml +559 -0
  114. data/spec/data/mac_users/10.7.shadow.xml +11 -0
  115. data/spec/data/mac_users/10.8.plist.xml +559 -0
  116. data/spec/data/mac_users/10.8.shadow.xml +21 -0
  117. data/spec/data/mac_users/10.9.plist.xml +560 -0
  118. data/spec/data/mac_users/10.9.shadow.xml +21 -0
  119. data/spec/data/object_loader/environments/test.json +2 -0
  120. data/spec/data/object_loader/environments/test_json_class.json +2 -0
  121. data/spec/data/object_loader/nodes/test.json +2 -0
  122. data/spec/data/object_loader/nodes/test_json_class.json +2 -0
  123. data/spec/data/object_loader/roles/test.json +2 -0
  124. data/spec/data/object_loader/roles/test_json_class.json +2 -0
  125. data/spec/functional/resource/bff_spec.rb +1 -1
  126. data/spec/functional/resource/cron_spec.rb +20 -1
  127. data/spec/functional/resource/env_spec.rb +137 -0
  128. data/spec/functional/resource/group_spec.rb +7 -5
  129. data/spec/functional/resource/remote_file_spec.rb +12 -1
  130. data/spec/functional/resource/user/dscl_spec.rb +198 -0
  131. data/spec/functional/resource/{user_spec.rb → user/useradd_spec.rb} +175 -37
  132. data/spec/integration/client/client_spec.rb +6 -4
  133. data/spec/integration/client/ipv6_spec.rb +16 -14
  134. data/spec/integration/knife/chef_fs_data_store_spec.rb +57 -46
  135. data/spec/integration/knife/chef_repo_path_spec.rb +105 -78
  136. data/spec/integration/knife/chef_repository_file_system_spec.rb +100 -84
  137. data/spec/integration/knife/chefignore_spec.rb +76 -46
  138. data/spec/integration/knife/common_options_spec.rb +16 -21
  139. data/spec/integration/knife/cookbook_api_ipv6_spec.rb +3 -3
  140. data/spec/integration/knife/delete_spec.rb +66 -46
  141. data/spec/integration/knife/deps_spec.rb +145 -94
  142. data/spec/integration/knife/diff_spec.rb +176 -110
  143. data/spec/integration/knife/download_spec.rb +229 -133
  144. data/spec/integration/knife/list_spec.rb +62 -54
  145. data/spec/integration/knife/raw_spec.rb +24 -9
  146. data/spec/integration/knife/redirection_spec.rb +2 -2
  147. data/spec/integration/knife/serve_spec.rb +2 -2
  148. data/spec/integration/knife/show_spec.rb +32 -26
  149. data/spec/integration/knife/upload_spec.rb +308 -165
  150. data/spec/integration/recipes/lwrp_inline_resources_spec.rb +10 -8
  151. data/spec/integration/solo/solo_spec.rb +22 -11
  152. data/spec/spec_helper.rb +3 -0
  153. data/spec/support/lib/chef/resource/zen_follower.rb +46 -0
  154. data/spec/support/platform_helpers.rb +12 -0
  155. data/spec/support/shared/functional/file_resource.rb +10 -0
  156. data/spec/support/shared/integration/chef_zero_support.rb +130 -0
  157. data/spec/support/shared/integration/integration_helper.rb +100 -98
  158. data/spec/support/shared/integration/knife_support.rb +0 -1
  159. data/spec/support/shared/unit/provider/file.rb +6 -4
  160. data/spec/support/shared/unit/provider/useradd_based_user_provider.rb +10 -1
  161. data/spec/unit/api_client/registration_spec.rb +83 -74
  162. data/spec/unit/application_spec.rb +32 -9
  163. data/spec/unit/cookbook/cookbook_version_loader_spec.rb +179 -0
  164. data/spec/unit/cookbook/metadata_spec.rb +190 -150
  165. data/spec/unit/cookbook/syntax_check_spec.rb +3 -2
  166. data/spec/unit/cookbook_loader_spec.rb +114 -53
  167. data/spec/unit/{cookbook_site_streaming_uploader.rb → cookbook_site_streaming_uploader_spec.rb} +21 -1
  168. data/spec/unit/data_bag_spec.rb +88 -13
  169. data/spec/unit/deprecation_spec.rb +1 -2
  170. data/spec/unit/encrypted_data_bag_item_spec.rb +145 -9
  171. data/spec/unit/environment_spec.rb +1 -1
  172. data/spec/unit/formatters/base_spec.rb +48 -0
  173. data/spec/unit/json_compat_spec.rb +48 -17
  174. data/spec/unit/knife/client_delete_spec.rb +4 -4
  175. data/spec/unit/knife/client_show_spec.rb +15 -5
  176. data/spec/unit/knife/cookbook_site_download_spec.rb +1 -1
  177. data/spec/unit/knife/cookbook_site_share_spec.rb +3 -3
  178. data/spec/unit/knife/data_bag_from_file_spec.rb +0 -2
  179. data/spec/unit/knife/data_bag_show_spec.rb +23 -14
  180. data/spec/unit/knife/node_show_spec.rb +32 -15
  181. data/spec/unit/knife/role_show_spec.rb +59 -0
  182. data/spec/unit/platform_spec.rb +10 -0
  183. data/spec/unit/provider/deploy_spec.rb +4 -0
  184. data/spec/unit/provider/env_spec.rb +19 -0
  185. data/spec/unit/provider/git_spec.rb +22 -2
  186. data/spec/unit/provider/group/dscl_spec.rb +38 -1
  187. data/spec/unit/provider/group/pw_spec.rb +2 -2
  188. data/spec/unit/provider/http_request_spec.rb +8 -8
  189. data/spec/unit/provider/log_spec.rb +33 -53
  190. data/spec/unit/provider/mount/mount_spec.rb +12 -3
  191. data/spec/unit/provider/package/ips_spec.rb +96 -63
  192. data/spec/unit/provider/package/paludis_spec.rb +5 -5
  193. data/spec/unit/provider/package/rpm_spec.rb +12 -0
  194. data/spec/unit/provider/package/zypper_spec.rb +28 -16
  195. data/spec/unit/provider/service/windows_spec.rb +77 -17
  196. data/spec/unit/provider/user/dscl_spec.rb +659 -264
  197. data/spec/unit/provider/user/useradd_spec.rb +1 -0
  198. data/spec/unit/recipe_spec.rb +41 -0
  199. data/spec/unit/resource/scm_spec.rb +11 -0
  200. data/spec/unit/resource/user_spec.rb +4 -0
  201. data/spec/unit/resource/windows_service_spec.rb +46 -0
  202. data/spec/unit/resource_collection_spec.rb +33 -0
  203. data/spec/unit/resource_reporter_spec.rb +48 -0
  204. data/spec/unit/resource_spec.rb +9 -2
  205. data/spec/unit/role_spec.rb +6 -0
  206. data/spec/unit/version_constraint_spec.rb +28 -0
  207. metadata +61 -4
@@ -54,16 +54,16 @@ class Chef
54
54
 
55
55
  def to_hash
56
56
  result = {
57
- "name" => @name,
57
+ 'name' => @name,
58
58
  'json_class' => self.class.name,
59
- "chef_type" => "data_bag",
59
+ 'chef_type' => 'data_bag',
60
60
  }
61
61
  result
62
62
  end
63
63
 
64
64
  # Serialize this object as a hash
65
65
  def to_json(*a)
66
- to_hash.to_json(*a)
66
+ Chef::JSONCompat.to_json(to_hash, *a)
67
67
  end
68
68
 
69
69
  def chef_server_rest
@@ -83,11 +83,15 @@ class Chef
83
83
 
84
84
  def self.list(inflate=false)
85
85
  if Chef::Config[:solo]
86
- unless File.directory?(Chef::Config[:data_bag_path])
87
- raise Chef::Exceptions::InvalidDataBagPath, "Data bag path '#{Chef::Config[:data_bag_path]}' is invalid"
88
- end
86
+ paths = Array(Chef::Config[:data_bag_path])
87
+ names = []
88
+ paths.each do |path|
89
+ unless File.directory?(path)
90
+ raise Chef::Exceptions::InvalidDataBagPath, "Data bag path '#{path}' is invalid"
91
+ end
89
92
 
90
- names = Dir.glob(File.join(Chef::Config[:data_bag_path], "*")).map{|f|File.basename(f)}.sort
93
+ names += Dir.glob(File.join(path, "*")).map{|f|File.basename(f)}.sort
94
+ end
91
95
  names.inject({}) {|h, n| h[n] = n; h}
92
96
  else
93
97
  if inflate
@@ -105,15 +109,25 @@ class Chef
105
109
  # Load a Data Bag by name via either the RESTful API or local data_bag_path if run in solo mode
106
110
  def self.load(name)
107
111
  if Chef::Config[:solo]
108
- unless File.directory?(Chef::Config[:data_bag_path])
109
- raise Chef::Exceptions::InvalidDataBagPath, "Data bag path '#{Chef::Config[:data_bag_path]}' is invalid"
110
- end
112
+ paths = Array(Chef::Config[:data_bag_path])
113
+ data_bag = {}
114
+ paths.each do |path|
115
+ unless File.directory?(path)
116
+ raise Chef::Exceptions::InvalidDataBagPath, "Data bag path '#{path}' is invalid"
117
+ end
118
+
119
+ Dir.glob(File.join(path, name.to_s, "*.json")).inject({}) do |bag, f|
120
+ item = Chef::JSONCompat.from_json(IO.read(f))
111
121
 
112
- Dir.glob(File.join(Chef::Config[:data_bag_path], "#{name}", "*.json")).inject({}) do |bag, f|
113
- item = Chef::JSONCompat.from_json(IO.read(f))
114
- bag[item['id']] = item
115
- bag
122
+ # Check if we have multiple items with similar names (ids) and raise if their content differs
123
+ if data_bag.has_key?(item["id"]) && data_bag[item["id"]] != item
124
+ raise Chef::Exceptions::DuplicateDataBagItem, "Data bag '#{name}' has items with the same name '#{item["id"]}' but different content."
125
+ else
126
+ data_bag[item["id"]] = item
127
+ end
128
+ end
116
129
  end
130
+ return data_bag
117
131
  else
118
132
  Chef::REST.new(Chef::Config[:chef_server_url]).get_rest("data/#{name}")
119
133
  end
@@ -150,4 +164,3 @@ class Chef
150
164
 
151
165
  end
152
166
  end
153
-
@@ -112,13 +112,13 @@ class Chef
112
112
  # Serialize this object as a hash
113
113
  def to_json(*a)
114
114
  result = {
115
- "name" => self.object_name,
115
+ "name" => object_name,
116
116
  "json_class" => self.class.name,
117
- "chef_type" => "data_bag_item",
118
- "data_bag" => self.data_bag,
119
- "raw_data" => self.raw_data
117
+ "chef_type" => "data_bag_item",
118
+ "data_bag" => data_bag,
119
+ "raw_data" => raw_data
120
120
  }
121
- result.to_json(*a)
121
+ Chef::JSONCompat.to_json(result, *a)
122
122
  end
123
123
 
124
124
  def self.from_hash(h)
@@ -210,5 +210,3 @@ class Chef
210
210
 
211
211
  end
212
212
  end
213
-
214
-
@@ -18,14 +18,11 @@
18
18
  # limitations under the License.
19
19
  #
20
20
 
21
- require 'digest'
21
+ require 'openssl'
22
22
 
23
23
  class Chef
24
24
  class Digester
25
-
26
- def self.instance
27
- @instance ||= new
28
- end
25
+ include Singleton
29
26
 
30
27
  def self.checksum_for_file(*args)
31
28
  instance.checksum_for_file(*args)
@@ -40,7 +37,7 @@ class Chef
40
37
  end
41
38
 
42
39
  def generate_checksum(file)
43
- checksum_file(file, Digest::SHA256.new)
40
+ checksum_file(file, OpenSSL::Digest::SHA256.new)
44
41
  end
45
42
 
46
43
  def self.generate_md5_checksum_for_file(*args)
@@ -48,11 +45,11 @@ class Chef
48
45
  end
49
46
 
50
47
  def generate_md5_checksum_for_file(file)
51
- checksum_file(file, Digest::MD5.new)
48
+ checksum_file(file, OpenSSL::Digest::MD5.new)
52
49
  end
53
50
 
54
51
  def generate_md5_checksum(io)
55
- checksum_io(io, Digest::MD5.new)
52
+ checksum_io(io, OpenSSL::Digest::MD5.new)
56
53
  end
57
54
 
58
55
  private
@@ -70,4 +67,3 @@ class Chef
70
67
 
71
68
  end
72
69
  end
73
-
@@ -85,6 +85,20 @@ class Chef
85
85
 
86
86
  resource = build_resource(type, name, created_at, &resource_attrs_block)
87
87
 
88
+ # Some resources (freebsd_package) can be invoked with multiple names
89
+ # (package || freebsd_package).
90
+ # https://github.com/opscode/chef/issues/1773
91
+ # For these resources we want to make sure
92
+ # their key in resource collection is same as the name they are declared
93
+ # as. Since this might be a breaking change for resources that define
94
+ # customer to_s methods, we are working around the issue by letting
95
+ # resources know of their created_as_type until this issue is fixed in
96
+ # Chef 12:
97
+ # https://github.com/opscode/chef/issues/1817
98
+ if resource.respond_to?(:created_as_type=)
99
+ resource.created_as_type = type
100
+ end
101
+
88
102
  run_context.resource_collection.insert(resource)
89
103
  resource
90
104
  end
@@ -48,6 +48,7 @@ require 'open-uri'
48
48
  #
49
49
  class Chef::EncryptedDataBagItem
50
50
  ALGORITHM = 'aes-256-cbc'
51
+ AEAD_ALGORITHM = 'aes-256-gcm'
51
52
 
52
53
  #
53
54
  # === Synopsis
@@ -0,0 +1,57 @@
1
+ #
2
+ # Author:: Xabier de Zuazo (<xabier@onddo.com>)
3
+ # Copyright:: Copyright (c) 2014 Onddo Labs, SL.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # 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
+
19
+ require 'chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format'
20
+ require 'chef/encrypted_data_bag_item/unsupported_cipher'
21
+
22
+ class Chef::EncryptedDataBagItem
23
+
24
+ class EncryptedDataBagRequirementsFailure < StandardError
25
+ end
26
+
27
+ module Assertions
28
+
29
+ def assert_format_version_acceptable!(format_version)
30
+ unless format_version.kind_of?(Integer) and format_version >= Chef::Config[:data_bag_decrypt_minimum_version]
31
+ raise UnacceptableEncryptedDataBagItemFormat,
32
+ "The encrypted data bag item has format version `#{format_version}', " +
33
+ "but the config setting 'data_bag_decrypt_minimum_version' requires version `#{Chef::Config[:data_bag_decrypt_minimum_version]}'"
34
+ end
35
+ end
36
+
37
+ def assert_valid_cipher!(requested_cipher, algorithm)
38
+ # In the future, chef may support configurable ciphers. For now, only
39
+ # aes-256-cbc and aes-256-gcm are supported.
40
+ unless requested_cipher == algorithm
41
+ raise UnsupportedCipher,
42
+ "Cipher '#{requested_cipher}' is not supported by this version of Chef. Available ciphers: ['#{ALGORITHM}', '#{AEAD_ALGORITHM}']"
43
+ end
44
+ end
45
+
46
+ def assert_aead_requirements_met!(algorithm)
47
+ unless OpenSSL::Cipher.method_defined?(:auth_data=)
48
+ raise EncryptedDataBagRequirementsFailure, "The used Encrypted Data Bags version requires Ruby >= 1.9"
49
+ end
50
+ unless OpenSSL::Cipher.ciphers.include?(algorithm)
51
+ raise EncryptedDataBagRequirementsFailure, "The used Encrypted Data Bags version requires an OpenSSL version with \"#{algorithm}\" algorithm support"
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -17,15 +17,14 @@
17
17
  #
18
18
 
19
19
  require 'yaml'
20
- require 'ffi_yajl'
20
+ require 'chef/json_compat'
21
21
  require 'openssl'
22
22
  require 'base64'
23
23
  require 'digest/sha2'
24
24
  require 'chef/encrypted_data_bag_item'
25
25
  require 'chef/encrypted_data_bag_item/unsupported_encrypted_data_bag_item_format'
26
- require 'chef/encrypted_data_bag_item/unacceptable_encrypted_data_bag_item_format'
27
26
  require 'chef/encrypted_data_bag_item/decryption_failure'
28
- require 'chef/encrypted_data_bag_item/unsupported_cipher'
27
+ require 'chef/encrypted_data_bag_item/assertions'
29
28
 
30
29
  class Chef::EncryptedDataBagItem
31
30
 
@@ -37,6 +36,7 @@ class Chef::EncryptedDataBagItem
37
36
  # to create an instance of the appropriate strategy for the given encrypted
38
37
  # data bag value.
39
38
  module Decryptor
39
+ extend Chef::EncryptedDataBagItem::Assertions
40
40
 
41
41
  # Detects the encrypted data bag item format version and instantiates a
42
42
  # decryptor object for that version. Call #for_decrypted_item on the
@@ -45,6 +45,8 @@ class Chef::EncryptedDataBagItem
45
45
  format_version = format_version_of(encrypted_value)
46
46
  assert_format_version_acceptable!(format_version)
47
47
  case format_version
48
+ when 3
49
+ Version3Decryptor.new(encrypted_value, key)
48
50
  when 2
49
51
  Version2Decryptor.new(encrypted_value, key)
50
52
  when 1
@@ -65,15 +67,8 @@ class Chef::EncryptedDataBagItem
65
67
  end
66
68
  end
67
69
 
68
- def self.assert_format_version_acceptable!(format_version)
69
- unless format_version.kind_of?(Integer) and format_version >= Chef::Config[:data_bag_decrypt_minimum_version]
70
- raise UnacceptableEncryptedDataBagItemFormat,
71
- "The encrypted data bag item has format version `#{format_version}', " +
72
- "but the config setting 'data_bag_decrypt_minimum_version' requires version `#{Chef::Config[:data_bag_decrypt_minimum_version]}'"
73
- end
74
- end
75
-
76
70
  class Version0Decryptor
71
+ include Chef::EncryptedDataBagItem::Assertions
77
72
 
78
73
  attr_reader :encrypted_data
79
74
  attr_reader :key
@@ -83,6 +78,11 @@ class Chef::EncryptedDataBagItem
83
78
  @key = key
84
79
  end
85
80
 
81
+ # Returns the used decryption algorithm
82
+ def algorithm
83
+ ALGORITHM
84
+ end
85
+
86
86
  def for_decrypted_item
87
87
  YAML.load(decrypted_data)
88
88
  end
@@ -102,7 +102,7 @@ class Chef::EncryptedDataBagItem
102
102
 
103
103
  def openssl_decryptor
104
104
  @openssl_decryptor ||= begin
105
- d = OpenSSL::Cipher::Cipher.new(ALGORITHM)
105
+ d = OpenSSL::Cipher.new(algorithm)
106
106
  d.decrypt
107
107
  d.pkcs5_keyivgen(key)
108
108
  d
@@ -110,7 +110,7 @@ class Chef::EncryptedDataBagItem
110
110
  end
111
111
  end
112
112
 
113
- class Version1Decryptor
113
+ class Version1Decryptor < Version0Decryptor
114
114
 
115
115
  attr_reader :encrypted_data
116
116
  attr_reader :key
@@ -121,8 +121,8 @@ class Chef::EncryptedDataBagItem
121
121
  end
122
122
 
123
123
  def for_decrypted_item
124
- FFI_Yajl::Parser.parse(decrypted_data)["json_wrapper"]
125
- rescue FFI_Yajl::ParseError
124
+ Chef::JSONCompat.parse(decrypted_data)["json_wrapper"]
125
+ rescue Chef::Exceptions::JSON::ParseError
126
126
  # convert to a DecryptionFailure error because the most likely scenario
127
127
  # here is that the decryption step was unsuccessful but returned bad
128
128
  # data rather than raising an error.
@@ -148,24 +148,16 @@ class Chef::EncryptedDataBagItem
148
148
 
149
149
  def openssl_decryptor
150
150
  @openssl_decryptor ||= begin
151
- assert_valid_cipher!
152
- d = OpenSSL::Cipher::Cipher.new(ALGORITHM)
151
+ assert_valid_cipher!(@encrypted_data["cipher"], algorithm)
152
+ d = OpenSSL::Cipher.new(algorithm)
153
153
  d.decrypt
154
- d.key = Digest::SHA256.digest(key)
154
+ # We must set key before iv: https://bugs.ruby-lang.org/issues/8221
155
+ d.key = OpenSSL::Digest::SHA256.digest(key)
155
156
  d.iv = iv
156
157
  d
157
158
  end
158
159
  end
159
160
 
160
- def assert_valid_cipher!
161
- # In the future, chef may support configurable ciphers. For now, only
162
- # aes-256-cbc is supported.
163
- requested_cipher = @encrypted_data["cipher"]
164
- unless requested_cipher == ALGORITHM
165
- raise UnsupportedCipher,
166
- "Cipher '#{requested_cipher}' is not supported by this version of Chef. Available ciphers: ['#{ALGORITHM}']"
167
- end
168
- end
169
161
  end
170
162
 
171
163
  class Version2Decryptor < Version1Decryptor
@@ -176,7 +168,7 @@ class Chef::EncryptedDataBagItem
176
168
  end
177
169
 
178
170
  def validate_hmac!
179
- digest = OpenSSL::Digest::Digest.new("sha256")
171
+ digest = OpenSSL::Digest.new("sha256")
180
172
  raw_hmac = OpenSSL::HMAC.digest(digest, key, @encrypted_data["encrypted_data"])
181
173
 
182
174
  if candidate_hmac_matches?(raw_hmac)
@@ -197,5 +189,37 @@ class Chef::EncryptedDataBagItem
197
189
  valid == 0
198
190
  end
199
191
  end
192
+
193
+ class Version3Decryptor < Version1Decryptor
194
+
195
+ def initialize(encrypted_data, key)
196
+ super
197
+ assert_aead_requirements_met!(algorithm)
198
+ end
199
+
200
+ # Returns the used decryption algorithm
201
+ def algorithm
202
+ AEAD_ALGORITHM
203
+ end
204
+
205
+ def auth_tag
206
+ auth_tag_b64 = @encrypted_data["auth_tag"]
207
+ if auth_tag_b64.nil?
208
+ raise DecryptionFailure, "Error decrypting data bag value: invalid authentication tag. Most likely the data is corrupted"
209
+ end
210
+ Base64.decode64(auth_tag_b64)
211
+ end
212
+
213
+ def openssl_decryptor
214
+ @openssl_decryptor ||= begin
215
+ d = super
216
+ d.auth_tag = auth_tag
217
+ d.auth_data = ''
218
+ d
219
+ end
220
+ end
221
+
222
+ end
223
+
200
224
  end
201
225
  end
@@ -0,0 +1,37 @@
1
+ #
2
+ # Author:: Xabier de Zuazo (<xabier@onddo.com>)
3
+ # Copyright:: Copyright (c) 2014 Onddo Labs, SL.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # 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
+
19
+ class Chef::EncryptedDataBagItem
20
+
21
+ class EncryptedDataBagRequirementsFailure < StandardError
22
+ end
23
+
24
+ module Assertions
25
+
26
+ def assert_requirements_met!
27
+ unless OpenSSL::Cipher.method_defined?(:auth_data=)
28
+ raise EncryptedDataBagRequirementsFailure, "The used Encrypted Data Bags version requires Ruby >= 1.9"
29
+ end
30
+ unless OpenSSL::Cipher.ciphers.include?(algorithm)
31
+ raise EncryptedDataBagRequirementsFailure, "The used Encrypted Data Bags version requires an OpenSSL version with \"#{algorithm}\" algorithm support"
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,22 @@
1
+ #
2
+ # Author:: Xabier de Zuazo (<xabier@onddo.com>)
3
+ # Copyright:: Copyright (c) 2014 Onddo Labs, SL.
4
+ # License:: Apache License, Version 2.0
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # 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
+
19
+ class Chef::EncryptedDataBagItem
20
+ class EncryptionFailure < StandardError
21
+ end
22
+ end