chef-encrypted-attributes 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.yardopts +8 -0
  5. data/CHANGELOG.md +40 -4
  6. data/CONTRIBUTING.md +7 -6
  7. data/KNIFE.md +151 -0
  8. data/README.md +70 -192
  9. data/Rakefile +27 -14
  10. data/TESTING.md +18 -7
  11. data/TODO.md +2 -5
  12. data/lib/chef-encrypted-attributes.rb +7 -1
  13. data/lib/chef/encrypted_attribute.rb +282 -121
  14. data/lib/chef/encrypted_attribute/api.rb +521 -0
  15. data/lib/chef/encrypted_attribute/assertions.rb +16 -6
  16. data/lib/chef/encrypted_attribute/cache_lru.rb +54 -13
  17. data/lib/chef/encrypted_attribute/config.rb +198 -89
  18. data/lib/chef/encrypted_attribute/encrypted_mash.rb +127 -33
  19. data/lib/chef/encrypted_attribute/encrypted_mash/version0.rb +236 -48
  20. data/lib/chef/encrypted_attribute/encrypted_mash/version1.rb +249 -36
  21. data/lib/chef/encrypted_attribute/encrypted_mash/version2.rb +133 -19
  22. data/lib/chef/encrypted_attribute/exceptions.rb +19 -3
  23. data/lib/chef/encrypted_attribute/local_node.rb +15 -4
  24. data/lib/chef/encrypted_attribute/remote_clients.rb +33 -17
  25. data/lib/chef/encrypted_attribute/remote_node.rb +84 -29
  26. data/lib/chef/encrypted_attribute/remote_nodes.rb +62 -11
  27. data/lib/chef/encrypted_attribute/remote_users.rb +58 -19
  28. data/lib/chef/encrypted_attribute/search_helper.rb +214 -74
  29. data/lib/chef/encrypted_attribute/version.rb +3 -1
  30. data/lib/chef/encrypted_attributes.rb +20 -0
  31. data/lib/chef/knife/core/config.rb +4 -1
  32. data/lib/chef/knife/core/encrypted_attribute_base.rb +179 -0
  33. data/lib/chef/knife/core/encrypted_attribute_depends.rb +43 -0
  34. data/lib/chef/knife/core/encrypted_attribute_editor_options.rb +125 -61
  35. data/lib/chef/knife/encrypted_attribute_create.rb +51 -31
  36. data/lib/chef/knife/encrypted_attribute_delete.rb +32 -40
  37. data/lib/chef/knife/encrypted_attribute_edit.rb +51 -32
  38. data/lib/chef/knife/encrypted_attribute_show.rb +30 -55
  39. data/lib/chef/knife/encrypted_attribute_update.rb +43 -28
  40. data/spec/benchmark_helper.rb +2 -1
  41. data/spec/integration_helper.rb +1 -0
  42. data/spec/spec_helper.rb +21 -7
  43. metadata +75 -36
  44. metadata.gz.sig +1 -1
  45. data/API.md +0 -174
  46. data/INTERNAL.md +0 -166
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  #
2
3
  # Author:: Xabier de Zuazo (<xabier@onddo.com>)
3
4
  # Copyright:: Copyright (c) 2014 Onddo Labs, SL. (www.onddo.com)
@@ -18,23 +19,38 @@
18
19
 
19
20
  class Chef
20
21
  class EncryptedAttribute
21
-
22
+ # Exception raised when some requirements to use the encrypted attributes
23
+ # are not met.
22
24
  class RequirementsFailure < StandardError; end
25
+ # Exception raised when the encrypted attribute format is unknown.
23
26
  class UnsupportedEncryptedAttributeFormat < StandardError; end
27
+ # Exception raised when the encrypted attribute format is wrong.
24
28
  class UnacceptableEncryptedAttributeFormat < StandardError; end
29
+ # Exception raised when there are decryption errors.
25
30
  class DecryptionFailure < StandardError; end
31
+ # Exception raised when there are encryption errors.
26
32
  class EncryptionFailure < StandardError; end
33
+ # Exception raised when there errors generating the HMAC.
27
34
  class MessageAuthenticationFailure < StandardError; end
35
+ # Exception raised when the public key is wrong.
28
36
  class InvalidPublicKey < StandardError; end
29
- class InvalidPrivateKey < StandardError; end
37
+ # Exception raised when the key is wrong.
38
+ class InvalidKey < StandardError; end
30
39
 
40
+ # Exception raised when you don't have enough privileges in the Chef Server
41
+ # to do what you intend. Usually happens when you try to read Client or Node
42
+ # keys without being admin.
31
43
  class InsufficientPrivileges < StandardError; end
44
+ # Exception raised when the user does not exist.
32
45
  class UserNotFound < StandardError; end
46
+ # Exception raised when the client does not exist.
33
47
  class ClientNotFound < StandardError; end
34
48
 
49
+ # Exception raised for search errors.
35
50
  class SearchFailure < StandardError; end
51
+ # Exception raised for search fatal errors.
36
52
  class SearchFatalError < StandardError; end
53
+ # Exception raised when search keys are wrong.
37
54
  class InvalidSearchKeys < StandardError; end
38
-
39
55
  end
40
56
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  #
2
3
  # Author:: Xabier de Zuazo (<xabier@onddo.com>)
3
4
  # Copyright:: Copyright (c) 2014 Onddo Labs, SL. (www.onddo.com)
@@ -18,21 +19,31 @@
18
19
 
19
20
  class Chef
20
21
  class EncryptedAttribute
22
+ # Get name and keys from local Chef Node.
21
23
  class LocalNode
22
-
23
- # currently not used
24
+ # Gets the local node name.
25
+ #
26
+ # @return [String] local node name.
27
+ # @note currently not used
24
28
  def name
25
29
  Chef::Config[:node_name]
26
30
  end
27
31
 
32
+ # Gets the local node key.
33
+ #
34
+ # The key has the private key and the public key embedded.
35
+ #
36
+ # @return [OpenSSL::PKey::RSA] the local node private and the public key.
28
37
  def key
29
- OpenSSL::PKey::RSA.new(open(Chef::Config[:client_key]).read())
38
+ OpenSSL::PKey::RSA.new(open(Chef::Config[:client_key]).read)
30
39
  end
31
40
 
41
+ # Gets the local node public key.
42
+ #
43
+ # @return [OpenSSL::PKey::RSA] the local node public key.
32
44
  def public_key
33
45
  key.public_key
34
46
  end
35
-
36
47
  end
37
48
  end
38
49
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  #
2
3
  # Author:: Xabier de Zuazo (<xabier@onddo.com>)
3
4
  # Copyright:: Copyright (c) 2014 Onddo Labs, SL. (www.onddo.com)
@@ -24,37 +25,52 @@ require 'chef/encrypted_attribute/cache_lru'
24
25
 
25
26
  class Chef
26
27
  class EncryptedAttribute
28
+ # Search remote Chef Clients public keys.
27
29
  class RemoteClients
28
30
  extend ::Chef::EncryptedAttribute::SearchHelper
29
31
 
32
+ # Remote clients search results cache.
33
+ #
34
+ # You can disable it setting it's size to zero:
35
+ #
36
+ # ```ruby
37
+ # Chef::EncryptedAttribute::RemoteClients.cache.max_size(0)
38
+ # ```
39
+ #
40
+ # @return [CacheLru] Remote clients LRU cache.
30
41
  def self.cache
31
42
  @@cache ||= Chef::EncryptedAttribute::CacheLru.new
32
43
  end
33
44
 
45
+ # Gets remote client public key.
46
+ #
47
+ # @param name [String] Chef client name.
48
+ # @return [String] Chef client public key as string.
49
+ # @raise [ClientNotFound] if client does not exist.
50
+ # @raise [Net::HTTPServerException] for Chef Server HTTP errors.
34
51
  def self.get_public_key(name)
35
52
  Chef::ApiClient.load(name).public_key
36
53
  rescue Net::HTTPServerException => e
37
- case e.response.code
38
- when '404' # Not Found
39
- raise ClientNotFound, "Chef Client not found: \"#{name}\"."
40
- else
41
- raise e
42
- end
54
+ raise e unless e.response.code == '404'
55
+ raise ClientNotFound, "Chef Client not found: #{name.inspect}."
43
56
  end
44
57
 
45
- def self.search_public_keys(search='*:*', partial_search=true)
58
+ # Searches for chef client public keys.
59
+ #
60
+ # @param search [Array<String>, String] search queries to perform, the
61
+ # query result will be *OR*-ed.
62
+ # @return [Array<String>] list of public keys.
63
+ # @raise [SearchFailure] if there is a Chef search error.
64
+ # @raise [SearchFatalError] if the Chef search response is wrong.
65
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
66
+ def self.search_public_keys(search = '*:*', partial_search = true)
46
67
  escaped_query = escape_query(search)
47
- if cache.has_key?(escaped_query)
48
- cache[escaped_query]
49
- else
50
- cache[escaped_query] = search(:client, search, {
51
- 'public_key' => [ 'public_key' ]
52
- }, 1000, partial_search).map do |client|
53
- client['public_key']
54
- end.compact
55
- end
68
+ return cache[escaped_query] if cache.key?(escaped_query)
69
+ cache[escaped_query] = search(
70
+ :client, search,
71
+ { 'public_key' => %w(public_key) }, 1000, partial_search
72
+ ).map { |client| client['public_key'] }.compact
56
73
  end
57
-
58
74
  end
59
75
  end
60
76
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  #
2
3
  # Author:: Xabier de Zuazo (<xabier@onddo.com>)
3
4
  # Copyright:: Copyright (c) 2014 Onddo Labs, SL. (www.onddo.com)
@@ -22,55 +23,77 @@ require 'chef/encrypted_attribute/cache_lru'
22
23
 
23
24
  class Chef
24
25
  class EncryptedAttribute
26
+ # Remote Node object to read and save node attributes remotely.
25
27
  class RemoteNode
26
28
  include ::Chef::Mixin::ParamsValidate
27
29
  include ::Chef::EncryptedAttribute::SearchHelper
28
30
 
31
+ # Remote Node object constructor.
32
+ #
33
+ # @param name [String] node name.
29
34
  def initialize(name)
30
35
  name(name)
31
36
  end
32
37
 
38
+ # Remote node attribute values cache.
39
+ #
40
+ # It is disabled by default. You can enable it changing it's size:
41
+ #
42
+ # ```ruby
43
+ # Chef::EncryptedAttribute::RemoteNode.cache.max_size(1024)
44
+ # ```
45
+ #
46
+ # @return [CacheLru] node attributes LRU cache.
33
47
  def self.cache
34
- @@cache ||= Chef::EncryptedAttribute::CacheLru.new(0) # disabled by default
48
+ # disabled by default
49
+ @@cache ||= Chef::EncryptedAttribute::CacheLru.new(0)
35
50
  end
36
51
 
37
- def name(arg=nil)
52
+ # Read or set node name.
53
+ #
54
+ # @param arg [String] node name.
55
+ # @return [String] node name.
56
+ def name(arg = nil)
57
+ # TODO: clean the cache when changed?
38
58
  set_or_return(
39
59
  :name,
40
60
  arg,
41
- :kind_of => String
61
+ kind_of: String
42
62
  )
43
63
  end
44
64
 
45
- def load_attribute(attr_ary, partial_search=true)
46
- unless attr_ary.kind_of?(Array)
47
- raise ArgumentError, "#{self.class.to_s}##{__method__} attr_ary argument must be an array of strings. You passed #{attr_ary.inspect}."
48
- end
65
+ # Loads a remote node attribute.
66
+ #
67
+ # @param attr_ary [Array<String>] node attribute path as Array.
68
+ # @param partial_search [Boolean] whether to use partial search.
69
+ # @return [Mixed] node attribute value.
70
+ # @raise [ArgumentError] if the attribute path format is wrong.
71
+ # @raise [SearchFailure] if there is a Chef search error.
72
+ # @raise [SearchFatalError] if the Chef search response is wrong.
73
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
74
+ def load_attribute(attr_ary, partial_search = true)
75
+ assert_attribute_array(attr_ary)
49
76
  cache_key = cache_key(name, attr_ary)
50
- if self.class.cache.has_key?(cache_key)
51
- self.class.cache[cache_key]
52
- else
53
- keys = { 'value' => attr_ary }
54
- res = search(:node, "name:#{@name}", keys, 1, partial_search)
55
- self.class.cache[cache_key] = if res.kind_of?(Array) and
56
- res[0].kind_of?(Hash) and res[0].has_key?('value')
57
- res[0]['value']
58
- else
59
- nil
60
- end
61
- end
77
+ return self.class.cache[cache_key] if self.class.cache.key?(cache_key)
78
+ keys = { 'value' => attr_ary }
79
+ res = search(:node, "name:#{@name}", keys, 1, partial_search)
80
+ self.class.cache[cache_key] = parse_search_result(res)
62
81
  end
63
82
 
83
+ # Saves a remote node attribute.
84
+ #
85
+ # @param attr_ary [Array<String>] node attribute path as Array.
86
+ # @param value [Mixed] node attribute value to set.
87
+ # @return [Mixed] node attribute value.
88
+ # @raise [ArgumentError] if the attribute path format is wrong.
64
89
  def save_attribute(attr_ary, value)
65
- unless attr_ary.kind_of?(Array)
66
- raise ArgumentError, "#{self.class.to_s}##{__method__} attr_ary argument must be an array of strings. You passed #{attr_ary.inspect}."
67
- end
90
+ assert_attribute_array(attr_ary)
68
91
  cache_key = cache_key(name, attr_ary)
69
92
 
70
93
  node = Chef::Node.load(name)
71
94
  last = attr_ary.pop
72
95
  node_attr = attr_ary.reduce(node.normal) do |a, k|
73
- a[k] = Mash.new unless a.has_key?(k)
96
+ a[k] = Mash.new unless a.key?(k)
74
97
  a[k]
75
98
  end
76
99
  node_attr[last] = value
@@ -79,18 +102,22 @@ class Chef
79
102
  self.class.cache[cache_key] = value
80
103
  end
81
104
 
105
+ # Deletes a remote node attribute.
106
+ #
107
+ # @param attr_ary [Array<String>] node attribute path as Array.
108
+ # @return [Boolean] whether the node attribute has been found and
109
+ # successfully deleted.
110
+ # @raise [ArgumentError] if the attribute path format is wrong.
82
111
  def delete_attribute(attr_ary)
83
- unless attr_ary.kind_of?(Array)
84
- raise ArgumentError, "#{self.class.to_s}##{__method__} attr_ary argument must be an array of strings. You passed #{attr_ary.inspect}."
85
- end
112
+ assert_attribute_array(attr_ary)
86
113
  cache_key = cache_key(name, attr_ary)
87
114
 
88
115
  node = Chef::Node.load(name)
89
116
  last = attr_ary.pop
90
117
  node_attr = attr_ary.reduce(node.normal) do |a, k|
91
- a.respond_to?(:has_key?) && a.has_key?(k) ? a[k] : nil
118
+ a.respond_to?(:key?) && a.key?(k) ? a[k] : nil
92
119
  end
93
- if node_attr.respond_to?(:has_key?) && node_attr.has_key?(last)
120
+ if node_attr.respond_to?(:key?) && node_attr.key?(last)
94
121
  node_attr.delete(last)
95
122
  node.save
96
123
  self.class.cache.delete(cache_key)
@@ -102,10 +129,38 @@ class Chef
102
129
 
103
130
  protected
104
131
 
132
+ # Parses {SearchHelper#search} result.
133
+ #
134
+ # @param res [Array<Hash>] {SearchHelper#search} result.
135
+ # @return [Mixed] final search result value.
136
+ def parse_search_result(res)
137
+ if res.is_a?(Array) && res[0].is_a?(Hash) && res[0].key?('value')
138
+ res[0]['value']
139
+ else
140
+ nil
141
+ end
142
+ end
143
+
144
+ # Generates the cache key.
145
+ #
146
+ # @param name [String] node name.
147
+ # @param attr_ary [Array<String>] node attribute path as Array.
148
+ # @return [String] cache key.
105
149
  def cache_key(name, attr_ary)
106
- "#{name}:#{attr_ary.inspect}" # TODO ok, this can be improved
150
+ "#{name}:#{attr_ary.inspect}" # TODO: OK, this can be improved
107
151
  end
108
152
 
153
+ # Asserts that the attribute path is in the correct format.
154
+ #
155
+ # @param attr_ary [Array<String>] node attribute path as Array.
156
+ # @return void
157
+ # @raise [ArgumentError] if the attribute path format is wrong.
158
+ def assert_attribute_array(attr_ary)
159
+ return if attr_ary.is_a?(Array)
160
+ fail ArgumentError,
161
+ "#{self.class}##{__method__} attr_ary argument must be an array "\
162
+ "of strings. You passed #{attr_ary.inspect}."
163
+ end
109
164
  end
110
165
  end
111
166
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  #
2
3
  # Author:: Xabier de Zuazo (<xabier@onddo.com>)
3
4
  # Copyright:: Copyright (c) 2014 Onddo Labs, SL. (www.onddo.com)
@@ -23,26 +24,76 @@ require 'chef/encrypted_attribute/remote_clients'
23
24
 
24
25
  class Chef
25
26
  class EncryptedAttribute
27
+ # Helpers to search nodes remotely and get it's public keys.
26
28
  class RemoteNodes
27
29
  extend ::Chef::EncryptedAttribute::SearchHelper
28
30
 
31
+ # Remote nodes search results cache.
32
+ #
33
+ # You can disable it setting it's size to zero:
34
+ #
35
+ # ```ruby
36
+ # Chef::EncryptedAttribute::RemoteNodes.cache.max_size(0)
37
+ # ```
38
+ #
39
+ # @return [CacheLru] Remote nodes LRU cache.
29
40
  def self.cache
30
41
  @@cache ||= Chef::EncryptedAttribute::CacheLru.new
31
42
  end
32
43
 
33
- def self.search_public_keys(search='*:*', partial_search=true)
34
- escaped_query = escape_query(search)
35
- if cache.has_key?(escaped_query)
36
- cache[escaped_query]
37
- else
38
- cache[escaped_query] = search(:node, search, {
39
- 'name' => [ 'name' ]
40
- }, 1000, partial_search).map do |node|
41
- RemoteClients.get_public_key(node['name'])
42
- end.compact
43
- end
44
+ # Gets remote node public key.
45
+ #
46
+ # It first tries to read the key from the `node['public_key']` attribute.
47
+ #
48
+ # If the `"public_key"` attribute does not exist, it tries to read the
49
+ # node client key directly using the Chef API (this require **admin**
50
+ # privileges).
51
+ #
52
+ # @param node [Chef::Node] Chef node object.
53
+ # @return [String] Chef client public key as string.
54
+ # @raise [InsufficientPrivileges] if you lack enoght privileges to read
55
+ # the keys from the Chef Server.
56
+ # @raise [ClientNotFound] if client does not exist.
57
+ # @raise [Net::HTTPServerException] for Chef Server HTTP errors.
58
+ def self.get_public_key(node)
59
+ return node['public_key'] unless node['public_key'].nil?
60
+ RemoteClients.get_public_key(node['name'])
61
+ rescue Net::HTTPServerException => e
62
+ raise e unless e.response.code == '403'
63
+ raise InsufficientPrivileges,
64
+ "You cannot read #{node['name']} client key. Consider including "\
65
+ 'the encrypted_attributes::expose_key recipe in the '\
66
+ "#{node['name']} node run list."
44
67
  end
45
68
 
69
+ # Searches for node client public keys.
70
+ #
71
+ # It first tries to read the key from the `node['public_key']` attribute.
72
+ #
73
+ # If the `"public_key"` attribute does not exist, it tries to read the
74
+ # node client key directly using the Chef API (this require **admin**
75
+ # privileges).
76
+ #
77
+ # @param search [Array<String>, String] search queries to perform, the
78
+ # query result will be *OR*-ed.
79
+ # @return [Array<String>] list of public keys.
80
+ # @raise [InsufficientPrivileges] if you lack enough privileges to read
81
+ # the keys from the Chef Server.
82
+ # @raise [ClientNotFound] if client does not exist.
83
+ # @raise [Net::HTTPServerException] for Chef Server HTTP errors.
84
+ # @raise [SearchFailure] if there is a Chef search error.
85
+ # @raise [SearchFatalError] if the Chef search response is wrong.
86
+ # @raise [InvalidSearchKeys] if search keys structure is wrong.
87
+ def self.search_public_keys(search = '*:*', partial_search = true)
88
+ escaped_query = escape_query(search)
89
+ return cache[escaped_query] if cache.key?(escaped_query)
90
+ cache[escaped_query] =
91
+ search(
92
+ :node, search,
93
+ { 'name' => %w(name), 'public_key' => %w(public_key) },
94
+ 1000, partial_search
95
+ ).map { |node| get_public_key(node) }.compact
96
+ end
46
97
  end
47
98
  end
48
99
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  #
2
3
  # Author:: Xabier de Zuazo (<xabier@onddo.com>)
3
4
  # Copyright:: Copyright (c) 2014 Onddo Labs, SL. (www.onddo.com)
@@ -22,52 +23,90 @@ require 'chef/encrypted_attribute/cache_lru'
22
23
 
23
24
  class Chef
24
25
  class EncryptedAttribute
26
+ # Helpers to get remote Chef Users keys.
27
+ #
28
+ # @note This class methods require **admin** privileges.
25
29
  class RemoteUsers
26
-
30
+ # Remote users public keys cache.
31
+ #
32
+ # You can disable it setting it's size to zero:
33
+ #
34
+ # ```ruby
35
+ # Chef::EncryptedAttribute::RemoteUsers.cache.max_size(0)
36
+ # ```
37
+ #
38
+ # @return [CacheLru] Remote users LRU cache.
27
39
  def self.cache
28
40
  @@cache ||= Chef::EncryptedAttribute::CacheLru.new
29
41
  end
30
42
 
31
- def self.get_public_keys(users=[])
43
+ # Gets some Chef users public keys.
44
+ #
45
+ # @note This method requires **admin** privileges.
46
+ #
47
+ # @param users [Array<String>, '*'] user list. Use `'*'` to get all users
48
+ # public keys.
49
+ # @return [Array<String>] public key list.
50
+ # @raise [ArgumentError] if user list is wrong.
51
+ def self.get_public_keys(users = [])
32
52
  if users == '*' # users are [a-z0-9\-_]+, cannot be *
33
- if cache.has_key?('*')
34
- cache['*']
35
- else
36
- cache['*'] = get_all_public_keys
37
- end
38
- elsif users.kind_of?(Array)
53
+ cache.key?('*') ? cache['*'] : cache['*'] = all_public_keys
54
+ elsif users.is_a?(Array)
39
55
  get_users_public_keys(users)
40
- elsif not users.nil?
41
- raise ArgumentError, "#{self.class.to_s}##{__method__} users argument must be an array or \"*\"."
56
+ elsif !users.nil?
57
+ fail ArgumentError,
58
+ "#{self.class}##{__method__} users argument must be an array "\
59
+ 'or "*".'
42
60
  end
43
61
  end
44
62
 
45
- protected
46
-
63
+ # Reads a Chef user public key.
64
+ #
65
+ # @note This method requires **admin** privileges.
66
+ #
67
+ # @param name [String] user name.
68
+ # @return [String] user public key as string.
69
+ # @raise [InsufficientPrivileges] if you lack enough privileges to read
70
+ # the keys from the Chef Server.
71
+ # @api private
47
72
  def self.get_user_public_key(name)
48
- return cache[name] if cache.has_key?(name)
73
+ return cache[name] if cache.key?(name)
49
74
  user = Chef::User.load(name)
50
75
  cache[name] = user.public_key
51
76
  rescue Net::HTTPServerException => e
52
77
  case e.response.code
53
78
  when '403'
54
- raise InsufficientPrivileges, 'Your node needs admin privileges to be able to work with Chef Users.'
55
- when '404' # Not Found
56
- raise UserNotFound, "Chef User not found: \"#{name}\"."
79
+ raise InsufficientPrivileges,
80
+ 'Your node needs admin privileges to be able to work with '\
81
+ 'Chef Users.'
82
+ when '404' then raise UserNotFound, "Chef User not found: \"#{name}\"."
57
83
  else
58
84
  raise e
59
85
  end
60
86
  end
61
87
 
88
+ # Gets some Chef users public keys.
89
+ #
90
+ # @note This method requires **admin** privileges.
91
+ #
92
+ # @param users [Array<String>] user list.
93
+ # @return [Array<String>] public key list.
94
+ # @api private
62
95
  def self.get_users_public_keys(users)
63
96
  users.map { |n| get_user_public_key(n) }
64
97
  end
65
98
 
66
- def self.get_all_public_keys
67
- # Chef::User.list(inflate=true) has a bug
99
+ # Gets all Chef users public keys.
100
+ #
101
+ # @note This method requires **admin** privileges.
102
+ #
103
+ # @return [Array<String>] public key list.
104
+ # @api private
105
+ def self.all_public_keys
106
+ # Chef::User.list(inflate=true) has a bug (fixed in 11.14.0)
107
+ # https://tickets.opscode.com/browse/CHEF-5328
68
108
  get_users_public_keys(Chef::User.list.keys)
69
109
  end
70
-
71
110
  end
72
111
  end
73
112
  end