From 0fa7040ce0d59fc76cd2f31343a3d7b1d3b8569c Mon Sep 17 00:00:00 2001 From: Marc Paradise Date: Fri, 26 Aug 2016 17:33:10 -0400 Subject: [PATCH] store ACEs by client/user Chef Server has the ability to return users and clients separately within an GET ACL request when `detail=granular`. To support that, we need to store them separately and determine if we want to present `actors` or `users` and `clients` at the time of the request. This change makes a reasonable best effort at capturing the creator type (user v client) correctly and uses that for determining its assignment in acls. --- lib/chef_zero/chef_data/data_normalizer.rb | 4 +- lib/chef_zero/chef_data/default_creator.rb | 51 +++++++++++++++++----- lib/chef_zero/endpoints/acls_endpoint.rb | 11 +++++ 3 files changed, 52 insertions(+), 14 deletions(-) diff --git a/lib/chef_zero/chef_data/data_normalizer.rb b/lib/chef_zero/chef_data/data_normalizer.rb index 0df7fe5a..58b0d26a 100644 --- a/lib/chef_zero/chef_data/data_normalizer.rb +++ b/lib/chef_zero/chef_data/data_normalizer.rb @@ -14,8 +14,8 @@ def self.normalize_acls(acls) # is the final list of actors that a subsequent GET will # provide. Each list is guaranteed to be unique, but the # combined list is not. - acls[perm]["actors"] = acls[perm].delete("users").uniq + - acls[perm].delete("clients").uniq + acls[perm]["actors"] = acls[perm]["clients"].uniq + + acls[perm]["users"].uniq else # this gets doubled sometimes, for reasons. (acls[perm]["actors"] ||= []).uniq! diff --git a/lib/chef_zero/chef_data/default_creator.rb b/lib/chef_zero/chef_data/default_creator.rb index 1ce62533..06181760 100644 --- a/lib/chef_zero/chef_data/default_creator.rb +++ b/lib/chef_zero/chef_data/default_creator.rb @@ -346,8 +346,7 @@ def get_org_acl_default(path) end def get_owners(acl_path) - owners = [] - + unknown_owners = [] path = AclPath.get_object_path(acl_path) if path @@ -356,10 +355,10 @@ def get_owners(acl_path) begin client = FFI_Yajl::Parser.parse(data.get(path), :create_additions => false) if !client["validator"] - owners |= [ path[3] ] + unknown_owners |= [ path[3] ] end rescue - owners |= [ path[3] ] + unknown_owners |= [ path[3] ] end # Add creators as owners (except any validator clients). @@ -370,33 +369,60 @@ def get_owners(acl_path) next if client["validator"] rescue end - owners |= [ creator ] + unknown_owners |= [ creator ] end end else - owners |= @creators[path] if @creators[path] + unknown_owners |= @creators[path] if @creators[path] end + owners = filter_owners(path, unknown_owners) #ANGRY # Non-default containers do not get superusers added to them, # because reasons. unless path.size == 4 && path[0] == "organizations" && path[2] == "containers" && !exists?(path) - owners += superusers + owners[:users] += superusers end + else + owners = { clients: [], users: [] } end - # we don't de-dup this list, because pedant expects to see ["pivotal", "pivotal"] in some cases. + owners[:users].uniq! + owners[:clients].uniq! + owners + end + + # Figures out if an object was created by a user or client. + # If the object does not exist in the context + # of an organization, it can only be a user + # + # This isn't perfect, because we are never explicitly told + # if a requestor creating an object is a user or client - + # but it gets us reasonably close + def filter_owners(path, unknown_owners) + owners = { clients: [], users: [] } + unknown_owners.each do |entity| + if path[0] == "organizations" && path.length > 2 + begin + data.get(["organizations", path[1], "clients", entity]) + owners[:clients] |= [ entity ] + rescue + owners[:users] |= [ entity ] + end + else + owners[:users] |= [ entity ] + end + end owners end def default_acl(acl_path, acl = {}) - owners = nil + owners = get_owners(acl_path) container_acl = nil PERMISSIONS.each do |perm| acl[perm] ||= {} - acl[perm]["actors"] ||= begin - owners ||= get_owners(acl_path) - end + acl[perm]["users"] = owners[:users] + acl[perm]["clients"] = owners[:clients] acl[perm]["groups"] ||= begin # When we create containers, we don't merge groups (not sure why). if acl_path[0] == "organizations" && acl_path[3] == "containers" @@ -406,6 +432,7 @@ def default_acl(acl_path, acl = {}) (container_acl[perm] ? container_acl[perm]["groups"] : []) || [] end end + acl[perm]["actors"] = acl[perm]["clients"] + acl[perm]["users"] end acl end diff --git a/lib/chef_zero/endpoints/acls_endpoint.rb b/lib/chef_zero/endpoints/acls_endpoint.rb index 8565eea5..f0ca0477 100644 --- a/lib/chef_zero/endpoints/acls_endpoint.rb +++ b/lib/chef_zero/endpoints/acls_endpoint.rb @@ -22,6 +22,17 @@ def get(request) end acls = FFI_Yajl::Parser.parse(get_data(request, acl_path), :create_additions => false) acls = ChefData::DataNormalizer.normalize_acls(acls) + if request.query_params["detail"] == "granular" + acls.each do |perm, ace| + acls[perm]["actors"] = [] + end + else + acls.each do |perm, ace| + acls[perm].delete("clients") + acls[perm].delete("users") + end + end + json_response(200, acls) end end