chef-zero 15.0.17 → 15.0.21

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 (122) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +36 -31
  3. data/LICENSE +201 -201
  4. data/Rakefile +73 -68
  5. data/bin/chef-zero +111 -111
  6. data/chef-zero.gemspec +34 -33
  7. data/lib/chef_zero/chef_data/acl_path.rb +140 -140
  8. data/lib/chef_zero/chef_data/cookbook_data.rb +237 -237
  9. data/lib/chef_zero/chef_data/data_normalizer.rb +276 -276
  10. data/lib/chef_zero/chef_data/default_creator.rb +476 -476
  11. data/lib/chef_zero/data_store/data_already_exists_error.rb +29 -29
  12. data/lib/chef_zero/data_store/data_error.rb +32 -32
  13. data/lib/chef_zero/data_store/data_not_found_error.rb +29 -29
  14. data/lib/chef_zero/data_store/default_facade.rb +143 -147
  15. data/lib/chef_zero/data_store/interface_v1.rb +67 -67
  16. data/lib/chef_zero/data_store/interface_v2.rb +18 -18
  17. data/lib/chef_zero/data_store/memory_store.rb +33 -33
  18. data/lib/chef_zero/data_store/memory_store_v2.rb +159 -159
  19. data/lib/chef_zero/data_store/raw_file_store.rb +143 -143
  20. data/lib/chef_zero/data_store/v1_to_v2_adapter.rb +150 -150
  21. data/lib/chef_zero/data_store/v2_to_v1_adapter.rb +105 -105
  22. data/lib/chef_zero/dist.rb +9 -9
  23. data/lib/chef_zero/endpoints/acl_endpoint.rb +39 -39
  24. data/lib/chef_zero/endpoints/acls_endpoint.rb +41 -41
  25. data/lib/chef_zero/endpoints/actor_default_key_endpoint.rb +78 -78
  26. data/lib/chef_zero/endpoints/actor_endpoint.rb +184 -184
  27. data/lib/chef_zero/endpoints/actor_key_endpoint.rb +62 -62
  28. data/lib/chef_zero/endpoints/actor_keys_endpoint.rb +129 -129
  29. data/lib/chef_zero/endpoints/actors_endpoint.rb +104 -104
  30. data/lib/chef_zero/endpoints/authenticate_user_endpoint.rb +32 -32
  31. data/lib/chef_zero/endpoints/container_endpoint.rb +22 -22
  32. data/lib/chef_zero/endpoints/containers_endpoint.rb +25 -25
  33. data/lib/chef_zero/endpoints/controls_endpoint.rb +16 -16
  34. data/lib/chef_zero/endpoints/cookbook_artifact_endpoint.rb +24 -24
  35. data/lib/chef_zero/endpoints/cookbook_artifact_identifier_endpoint.rb +68 -68
  36. data/lib/chef_zero/endpoints/cookbook_artifacts_endpoint.rb +34 -34
  37. data/lib/chef_zero/endpoints/cookbook_endpoint.rb +39 -39
  38. data/lib/chef_zero/endpoints/cookbook_version_endpoint.rb +136 -136
  39. data/lib/chef_zero/endpoints/cookbooks_base.rb +80 -80
  40. data/lib/chef_zero/endpoints/cookbooks_endpoint.rb +19 -19
  41. data/lib/chef_zero/endpoints/data_bag_endpoint.rb +45 -45
  42. data/lib/chef_zero/endpoints/data_bag_item_endpoint.rb +25 -25
  43. data/lib/chef_zero/endpoints/data_bags_endpoint.rb +23 -23
  44. data/lib/chef_zero/endpoints/dummy_endpoint.rb +29 -29
  45. data/lib/chef_zero/endpoints/environment_cookbook_endpoint.rb +24 -24
  46. data/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +126 -126
  47. data/lib/chef_zero/endpoints/environment_cookbooks_endpoint.rb +22 -22
  48. data/lib/chef_zero/endpoints/environment_endpoint.rb +33 -33
  49. data/lib/chef_zero/endpoints/environment_nodes_endpoint.rb +23 -23
  50. data/lib/chef_zero/endpoints/environment_recipes_endpoint.rb +22 -22
  51. data/lib/chef_zero/endpoints/environment_role_endpoint.rb +36 -36
  52. data/lib/chef_zero/endpoints/file_store_file_endpoint.rb +22 -22
  53. data/lib/chef_zero/endpoints/group_endpoint.rb +20 -20
  54. data/lib/chef_zero/endpoints/groups_endpoint.rb +13 -13
  55. data/lib/chef_zero/endpoints/license_endpoint.rb +25 -25
  56. data/lib/chef_zero/endpoints/node_endpoint.rb +34 -34
  57. data/lib/chef_zero/endpoints/node_identifiers_endpoint.rb +22 -22
  58. data/lib/chef_zero/endpoints/nodes_endpoint.rb +34 -34
  59. data/lib/chef_zero/endpoints/not_found_endpoint.rb +11 -11
  60. data/lib/chef_zero/endpoints/organization_association_request_endpoint.rb +22 -22
  61. data/lib/chef_zero/endpoints/organization_association_requests_endpoint.rb +30 -30
  62. data/lib/chef_zero/endpoints/organization_authenticate_user_endpoint.rb +26 -26
  63. data/lib/chef_zero/endpoints/organization_endpoint.rb +47 -47
  64. data/lib/chef_zero/endpoints/organization_user_base.rb +15 -15
  65. data/lib/chef_zero/endpoints/organization_user_default_key_endpoint.rb +16 -16
  66. data/lib/chef_zero/endpoints/organization_user_endpoint.rb +26 -26
  67. data/lib/chef_zero/endpoints/organization_user_key_endpoint.rb +17 -17
  68. data/lib/chef_zero/endpoints/organization_user_keys_endpoint.rb +17 -17
  69. data/lib/chef_zero/endpoints/organization_users_endpoint.rb +43 -43
  70. data/lib/chef_zero/endpoints/organization_validator_key_endpoint.rb +20 -20
  71. data/lib/chef_zero/endpoints/organizations_endpoint.rb +61 -61
  72. data/lib/chef_zero/endpoints/policies_endpoint.rb +26 -26
  73. data/lib/chef_zero/endpoints/policy_endpoint.rb +24 -24
  74. data/lib/chef_zero/endpoints/policy_group_endpoint.rb +46 -46
  75. data/lib/chef_zero/endpoints/policy_group_policy_endpoint.rb +83 -83
  76. data/lib/chef_zero/endpoints/policy_groups_endpoint.rb +38 -38
  77. data/lib/chef_zero/endpoints/policy_revision_endpoint.rb +66 -66
  78. data/lib/chef_zero/endpoints/policy_revisions_endpoint.rb +15 -15
  79. data/lib/chef_zero/endpoints/principal_endpoint.rb +55 -55
  80. data/lib/chef_zero/endpoints/rest_list_endpoint.rb +42 -42
  81. data/lib/chef_zero/endpoints/rest_object_endpoint.rb +78 -78
  82. data/lib/chef_zero/endpoints/role_endpoint.rb +16 -16
  83. data/lib/chef_zero/endpoints/role_environments_endpoint.rb +14 -14
  84. data/lib/chef_zero/endpoints/sandbox_endpoint.rb +27 -27
  85. data/lib/chef_zero/endpoints/sandboxes_endpoint.rb +51 -51
  86. data/lib/chef_zero/endpoints/search_endpoint.rb +208 -208
  87. data/lib/chef_zero/endpoints/searches_endpoint.rb +18 -18
  88. data/lib/chef_zero/endpoints/server_api_version_endpoint.rb +14 -14
  89. data/lib/chef_zero/endpoints/system_recovery_endpoint.rb +30 -30
  90. data/lib/chef_zero/endpoints/universe_endpoint.rb +15 -15
  91. data/lib/chef_zero/endpoints/user_association_request_endpoint.rb +41 -41
  92. data/lib/chef_zero/endpoints/user_association_requests_count_endpoint.rb +19 -19
  93. data/lib/chef_zero/endpoints/user_association_requests_endpoint.rb +19 -19
  94. data/lib/chef_zero/endpoints/user_organizations_endpoint.rb +22 -22
  95. data/lib/chef_zero/endpoints/version_endpoint.rb +13 -13
  96. data/lib/chef_zero/log.rb +7 -7
  97. data/lib/chef_zero/rest_base.rb +332 -332
  98. data/lib/chef_zero/rest_error_response.rb +11 -11
  99. data/lib/chef_zero/rest_request.rb +84 -88
  100. data/lib/chef_zero/rest_router.rb +72 -72
  101. data/lib/chef_zero/rspec.rb +355 -355
  102. data/lib/chef_zero/server.rb +730 -730
  103. data/lib/chef_zero/socketless_server_map.rb +92 -93
  104. data/lib/chef_zero/solr/query/binary_operator.rb +52 -52
  105. data/lib/chef_zero/solr/query/phrase.rb +23 -23
  106. data/lib/chef_zero/solr/query/range_query.rb +46 -46
  107. data/lib/chef_zero/solr/query/regexpable_query.rb +30 -30
  108. data/lib/chef_zero/solr/query/subquery.rb +37 -37
  109. data/lib/chef_zero/solr/query/term.rb +45 -45
  110. data/lib/chef_zero/solr/query/unary_operator.rb +41 -41
  111. data/lib/chef_zero/solr/solr_doc.rb +53 -53
  112. data/lib/chef_zero/solr/solr_parser.rb +208 -208
  113. data/lib/chef_zero/version.rb +3 -3
  114. data/lib/chef_zero.rb +10 -10
  115. data/spec/run_oc_pedant.rb +226 -226
  116. data/spec/search_spec.rb +36 -36
  117. data/spec/server_spec.rb +96 -96
  118. data/spec/socketless_server_map_spec.rb +74 -74
  119. data/spec/support/oc_pedant.rb +149 -149
  120. data/spec/support/secrets.json +6 -6
  121. data/spec/support/stickywicket.pem +27 -27
  122. metadata +35 -18
@@ -1,41 +1,41 @@
1
- require "ffi_yajl" unless defined?(FFI_Yajl)
2
- require_relative "../rest_base"
3
- require_relative "../chef_data/data_normalizer"
4
- require_relative "../chef_data/acl_path"
5
-
6
- module ChefZero
7
- module Endpoints
8
- # /organizations/ORG/THING/NAME/_acl
9
- # Where THING is:
10
- # - clients, data, containers, cookbooks, environments
11
- # groups, roles, nodes, users
12
- # or
13
- # /organizations/ORG/organization/_acl
14
- # /users/NAME/_acl
15
- class AclsEndpoint < RestBase
16
- def get(request)
17
- path = request.rest_path[0..-2] # Strip off _acl
18
- path = path[0..1] if path.size == 3 && path[0] == "organizations" && %w{organization organizations}.include?(path[2])
19
- acl_path = ChefData::AclPath.get_acl_data_path(path)
20
- unless acl_path
21
- raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
22
- end
23
-
24
- acls = FFI_Yajl::Parser.parse(get_data(request, acl_path))
25
- acls = ChefData::DataNormalizer.normalize_acls(acls)
26
- if request.query_params["detail"] == "granular"
27
- acls.each do |perm, ace|
28
- acls[perm]["actors"] = []
29
- end
30
- else
31
- acls.each do |perm, ace|
32
- acls[perm].delete("clients")
33
- acls[perm].delete("users")
34
- end
35
- end
36
-
37
- json_response(200, acls)
38
- end
39
- end
40
- end
41
- end
1
+ require "ffi_yajl" unless defined?(FFI_Yajl)
2
+ require_relative "../rest_base"
3
+ require_relative "../chef_data/data_normalizer"
4
+ require_relative "../chef_data/acl_path"
5
+
6
+ module ChefZero
7
+ module Endpoints
8
+ # /organizations/ORG/THING/NAME/_acl
9
+ # Where THING is:
10
+ # - clients, data, containers, cookbooks, environments
11
+ # groups, roles, nodes, users
12
+ # or
13
+ # /organizations/ORG/organization/_acl
14
+ # /users/NAME/_acl
15
+ class AclsEndpoint < RestBase
16
+ def get(request)
17
+ path = request.rest_path[0..-2] # Strip off _acl
18
+ path = path[0..1] if path.size == 3 && path[0] == "organizations" && %w{organization organizations}.include?(path[2])
19
+ acl_path = ChefData::AclPath.get_acl_data_path(path)
20
+ unless acl_path
21
+ raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
22
+ end
23
+
24
+ acls = FFI_Yajl::Parser.parse(get_data(request, acl_path))
25
+ acls = ChefData::DataNormalizer.normalize_acls(acls)
26
+ if request.query_params["detail"] == "granular"
27
+ acls.each do |perm, ace|
28
+ acls[perm]["actors"] = []
29
+ end
30
+ else
31
+ acls.each do |perm, ace|
32
+ acls[perm].delete("clients")
33
+ acls[perm].delete("users")
34
+ end
35
+ end
36
+
37
+ json_response(200, acls)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,78 +1,78 @@
1
- require_relative "../rest_base"
2
-
3
- module ChefZero
4
- module Endpoints
5
- # ActorDefaultKeyEndpoint
6
- #
7
- # This class handles DELETE/GET/PUT requests for client/user default public
8
- # keys, i.e. requests with identity key "default". All others are handled
9
- # by ActorKeyEndpoint.
10
- #
11
- # Default public keys are stored with the actor (client or user) instead of
12
- # under user/client_keys. Handling those in a separate endpoint offloads
13
- # the branching logic onto the router rather than branching in every
14
- # endpoint method (`if request.rest_path[-1] == "default" ...`).
15
- #
16
- # /users/USER/keys/default
17
- # /organizations/ORG/clients/CLIENT/keys/default
18
- class ActorDefaultKeyEndpoint < RestBase
19
- DEFAULT_PUBLIC_KEY_NAME = "default".freeze
20
-
21
- def get(request)
22
- # 404 if actor doesn't exist
23
- actor_data = get_actor_data(request)
24
- key_data = default_public_key_from_actor(actor_data)
25
-
26
- # 404 if the actor doesn't have a default key
27
- if key_data["public_key"].nil?
28
- raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
29
- end
30
-
31
- json_response(200, default_public_key_from_actor(actor_data))
32
- end
33
-
34
- def delete(request)
35
- path = actor_path(request)
36
- actor_data = get_actor_data(request) # 404 if actor doesn't exist
37
-
38
- default_public_key = delete_actor_default_public_key!(request, path, actor_data)
39
- json_response(200, default_public_key)
40
- end
41
-
42
- def put(request)
43
- # 404 if actor doesn't exist
44
- actor_data = get_actor_data(request)
45
-
46
- new_public_key = parse_json(request.body)["public_key"]
47
- actor_data["public_key"] = new_public_key
48
-
49
- set_data(request, actor_path(request), to_json(actor_data))
50
- end
51
-
52
- private
53
-
54
- def actor_path(request)
55
- return request.rest_path[0..3] if request.rest_path[2] == "clients"
56
-
57
- request.rest_path[0..1]
58
- end
59
-
60
- def get_actor_data(request)
61
- path = actor_path(request)
62
- parse_json(get_data(request, path))
63
- end
64
-
65
- def default_public_key_from_actor(actor_data)
66
- { "name" => DEFAULT_PUBLIC_KEY_NAME,
67
- "public_key" => actor_data["public_key"],
68
- "expiration_date" => "infinity" }
69
- end
70
-
71
- def delete_actor_default_public_key!(request, path, actor_data)
72
- new_actor_data = actor_data.merge("public_key" => nil)
73
- set_data(request, path, to_json(new_actor_data))
74
- default_public_key_from_actor(actor_data)
75
- end
76
- end
77
- end
78
- end
1
+ require_relative "../rest_base"
2
+
3
+ module ChefZero
4
+ module Endpoints
5
+ # ActorDefaultKeyEndpoint
6
+ #
7
+ # This class handles DELETE/GET/PUT requests for client/user default public
8
+ # keys, i.e. requests with identity key "default". All others are handled
9
+ # by ActorKeyEndpoint.
10
+ #
11
+ # Default public keys are stored with the actor (client or user) instead of
12
+ # under user/client_keys. Handling those in a separate endpoint offloads
13
+ # the branching logic onto the router rather than branching in every
14
+ # endpoint method (`if request.rest_path[-1] == "default" ...`).
15
+ #
16
+ # /users/USER/keys/default
17
+ # /organizations/ORG/clients/CLIENT/keys/default
18
+ class ActorDefaultKeyEndpoint < RestBase
19
+ DEFAULT_PUBLIC_KEY_NAME = "default".freeze
20
+
21
+ def get(request)
22
+ # 404 if actor doesn't exist
23
+ actor_data = get_actor_data(request)
24
+ key_data = default_public_key_from_actor(actor_data)
25
+
26
+ # 404 if the actor doesn't have a default key
27
+ if key_data["public_key"].nil?
28
+ raise RestErrorResponse.new(404, "Object not found: #{build_uri(request.base_uri, request.rest_path)}")
29
+ end
30
+
31
+ json_response(200, default_public_key_from_actor(actor_data))
32
+ end
33
+
34
+ def delete(request)
35
+ path = actor_path(request)
36
+ actor_data = get_actor_data(request) # 404 if actor doesn't exist
37
+
38
+ default_public_key = delete_actor_default_public_key!(request, path, actor_data)
39
+ json_response(200, default_public_key)
40
+ end
41
+
42
+ def put(request)
43
+ # 404 if actor doesn't exist
44
+ actor_data = get_actor_data(request)
45
+
46
+ new_public_key = parse_json(request.body)["public_key"]
47
+ actor_data["public_key"] = new_public_key
48
+
49
+ set_data(request, actor_path(request), to_json(actor_data))
50
+ end
51
+
52
+ private
53
+
54
+ def actor_path(request)
55
+ return request.rest_path[0..3] if request.rest_path[2] == "clients"
56
+
57
+ request.rest_path[0..1]
58
+ end
59
+
60
+ def get_actor_data(request)
61
+ path = actor_path(request)
62
+ parse_json(get_data(request, path))
63
+ end
64
+
65
+ def default_public_key_from_actor(actor_data)
66
+ { "name" => DEFAULT_PUBLIC_KEY_NAME,
67
+ "public_key" => actor_data["public_key"],
68
+ "expiration_date" => "infinity" }
69
+ end
70
+
71
+ def delete_actor_default_public_key!(request, path, actor_data)
72
+ new_actor_data = actor_data.merge("public_key" => nil)
73
+ set_data(request, path, to_json(new_actor_data))
74
+ default_public_key_from_actor(actor_data)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -1,184 +1,184 @@
1
- require "ffi_yajl" unless defined?(FFI_Yajl)
2
- require_relative "rest_object_endpoint"
3
- require_relative "../chef_data/data_normalizer"
4
-
5
- module ChefZero
6
- module Endpoints
7
- # /organizations/ORG/clients/NAME
8
- # /organizations/ORG/users/NAME
9
- # /users/NAME
10
- class ActorEndpoint < RestObjectEndpoint
11
-
12
- def get(request)
13
- result = super
14
- user_data = parse_json(result[2])
15
-
16
- user_data.delete("public_key") unless request.api_v0?
17
-
18
- json_response(200, user_data)
19
- end
20
-
21
- def delete(request)
22
- result = super
23
-
24
- if request.rest_path[0] == "users"
25
- list_data(request, [ "organizations" ]).each do |org|
26
- begin
27
- delete_data(request, [ "organizations", org, "users", request.rest_path[1] ], :data_store_exceptions)
28
- rescue DataStore::DataNotFoundError
29
- end
30
- end
31
- end
32
-
33
- delete_actor_keys!(request)
34
- result
35
- end
36
-
37
- def put(request)
38
- # Find out if we're updating the public key.
39
- request_body = FFI_Yajl::Parser.parse(request.body)
40
-
41
- if request_body["public_key"].nil?
42
- # If public_key is null, then don't overwrite it. Weird patchiness.
43
- body_modified = true
44
- request_body.delete("public_key")
45
- else
46
- updating_public_key = true
47
- end
48
-
49
- # Generate private_key if requested.
50
- if request_body.key?("private_key")
51
- body_modified = true
52
-
53
- if request_body.delete("private_key")
54
- private_key, public_key = server.gen_key_pair
55
- updating_public_key = true
56
- request_body["public_key"] = public_key
57
- end
58
- end
59
-
60
- # Put modified body back in `request.body`
61
- request.body = to_json(request_body) if body_modified
62
-
63
- # PUT /clients is patchy
64
- request.body = patch_request_body(request)
65
-
66
- result = super(request)
67
-
68
- # Inject private_key into response, delete public_key/password if applicable
69
- if result[0] == 200 || result[0] == 201
70
- client_or_user_name = identity_key_value(request) || request.rest_path[-1]
71
-
72
- if is_rename?(request)
73
- rename_keys!(request, client_or_user_name)
74
- end
75
-
76
- if request.rest_path[0] == "users"
77
- response = {
78
- "uri" => build_uri(request.base_uri, [ "users", client_or_user_name ]),
79
- }
80
- else
81
- response = parse_json(result[2])
82
- end
83
-
84
- if client?(request)
85
- response["private_key"] = private_key ? private_key : false
86
- else
87
- response["private_key"] = private_key if private_key
88
- response.delete("public_key") unless updating_public_key
89
- end
90
-
91
- response.delete("password")
92
-
93
- json_response(result[0], response)
94
- else
95
- result
96
- end
97
- end
98
-
99
- def populate_defaults(request, response_json)
100
- response = parse_json(response_json)
101
-
102
- populated_response =
103
- if client?(request)
104
- ChefData::DataNormalizer.normalize_client(
105
- response,
106
- response["name"] || request.rest_path[-1],
107
- request.rest_path[1]
108
- )
109
- else
110
- ChefData::DataNormalizer.normalize_user(
111
- response,
112
- response["username"] || request.rest_path[-1],
113
- identity_keys,
114
- server.options[:osc_compat],
115
- request.method
116
- )
117
- end
118
-
119
- to_json(populated_response)
120
- end
121
-
122
- private
123
-
124
- # Move key data to new path
125
- def rename_keys!(request, new_client_or_user_name)
126
- orig_keys_path = keys_path_base(request)
127
- new_keys_path = orig_keys_path.dup
128
- .tap { |path| path[-2] = new_client_or_user_name }
129
-
130
- key_names = list_data_or_else(request, orig_keys_path, nil)
131
- return unless key_names # No keys to move
132
-
133
- key_names.each do |key_name|
134
- # Get old data
135
- orig_path = [ *orig_keys_path, key_name ]
136
- data = get_data(request, orig_path, :data_store_exceptions)
137
-
138
- # Copy data to new path
139
- create_data(
140
- request,
141
- new_keys_path, key_name,
142
- data,
143
- :create_dir
144
- )
145
- end
146
-
147
- # Delete original data
148
- delete_data_dir(request, orig_keys_path, :recursive, :data_store_exceptions)
149
- end
150
-
151
- def delete_actor_keys!(request)
152
- path = keys_path_base(request)[0..-2]
153
- delete_data_dir(request, path, :recursive, :data_store_exceptions)
154
- rescue DataStore::DataNotFoundError
155
- end
156
-
157
- def client?(request, rest_path = nil)
158
- rest_path ||= request.rest_path
159
- rest_path[2] == "clients"
160
- end
161
-
162
- # Return the data store keys path for the request client or user, e.g.
163
- #
164
- # /organizations/ORG/clients/CLIENT -> /organizations/ORG/client_keys/CLIENT/keys
165
- # /organizations/ORG/users/USER -> /organizations/ORG/user_keys/USER/keys
166
- # /users/USER -> /user_keys/USER
167
- #
168
- def keys_path_base(request, client_or_user_name = nil)
169
- rest_path = (rest_path || request.rest_path).dup
170
- rest_path = rest_path.dup
171
- case rest_path[-2]
172
- when "users"
173
- rest_path[-2] = "user_keys"
174
- when "clients"
175
- rest_path[-2] = "client_keys"
176
- else
177
- raise "Unexpected URL #{rest_path.join("/")}: cannot determine key path"
178
- end
179
- rest_path << "keys"
180
- rest_path
181
- end
182
- end
183
- end
184
- end
1
+ require "ffi_yajl" unless defined?(FFI_Yajl)
2
+ require_relative "rest_object_endpoint"
3
+ require_relative "../chef_data/data_normalizer"
4
+
5
+ module ChefZero
6
+ module Endpoints
7
+ # /organizations/ORG/clients/NAME
8
+ # /organizations/ORG/users/NAME
9
+ # /users/NAME
10
+ class ActorEndpoint < RestObjectEndpoint
11
+
12
+ def get(request)
13
+ result = super
14
+ user_data = parse_json(result[2])
15
+
16
+ user_data.delete("public_key") unless request.api_v0?
17
+
18
+ json_response(200, user_data)
19
+ end
20
+
21
+ def delete(request)
22
+ result = super
23
+
24
+ if request.rest_path[0] == "users"
25
+ list_data(request, [ "organizations" ]).each do |org|
26
+
27
+ delete_data(request, [ "organizations", org, "users", request.rest_path[1] ], :data_store_exceptions)
28
+ rescue DataStore::DataNotFoundError
29
+
30
+ end
31
+ end
32
+
33
+ delete_actor_keys!(request)
34
+ result
35
+ end
36
+
37
+ def put(request)
38
+ # Find out if we're updating the public key.
39
+ request_body = FFI_Yajl::Parser.parse(request.body)
40
+
41
+ if request_body["public_key"].nil?
42
+ # If public_key is null, then don't overwrite it. Weird patchiness.
43
+ body_modified = true
44
+ request_body.delete("public_key")
45
+ else
46
+ updating_public_key = true
47
+ end
48
+
49
+ # Generate private_key if requested.
50
+ if request_body.key?("private_key")
51
+ body_modified = true
52
+
53
+ if request_body.delete("private_key")
54
+ private_key, public_key = server.gen_key_pair
55
+ updating_public_key = true
56
+ request_body["public_key"] = public_key
57
+ end
58
+ end
59
+
60
+ # Put modified body back in `request.body`
61
+ request.body = to_json(request_body) if body_modified
62
+
63
+ # PUT /clients is patchy
64
+ request.body = patch_request_body(request)
65
+
66
+ result = super(request)
67
+
68
+ # Inject private_key into response, delete public_key/password if applicable
69
+ if result[0] == 200 || result[0] == 201
70
+ client_or_user_name = identity_key_value(request) || request.rest_path[-1]
71
+
72
+ if is_rename?(request)
73
+ rename_keys!(request, client_or_user_name)
74
+ end
75
+
76
+ if request.rest_path[0] == "users"
77
+ response = {
78
+ "uri" => build_uri(request.base_uri, [ "users", client_or_user_name ]),
79
+ }
80
+ else
81
+ response = parse_json(result[2])
82
+ end
83
+
84
+ if client?(request)
85
+ response["private_key"] = private_key || false
86
+ else
87
+ response["private_key"] = private_key if private_key
88
+ response.delete("public_key") unless updating_public_key
89
+ end
90
+
91
+ response.delete("password")
92
+
93
+ json_response(result[0], response)
94
+ else
95
+ result
96
+ end
97
+ end
98
+
99
+ def populate_defaults(request, response_json)
100
+ response = parse_json(response_json)
101
+
102
+ populated_response =
103
+ if client?(request)
104
+ ChefData::DataNormalizer.normalize_client(
105
+ response,
106
+ response["name"] || request.rest_path[-1],
107
+ request.rest_path[1]
108
+ )
109
+ else
110
+ ChefData::DataNormalizer.normalize_user(
111
+ response,
112
+ response["username"] || request.rest_path[-1],
113
+ identity_keys,
114
+ server.options[:osc_compat],
115
+ request.method
116
+ )
117
+ end
118
+
119
+ to_json(populated_response)
120
+ end
121
+
122
+ private
123
+
124
+ # Move key data to new path
125
+ def rename_keys!(request, new_client_or_user_name)
126
+ orig_keys_path = keys_path_base(request)
127
+ new_keys_path = orig_keys_path.dup
128
+ .tap { |path| path[-2] = new_client_or_user_name }
129
+
130
+ key_names = list_data_or_else(request, orig_keys_path, nil)
131
+ return unless key_names # No keys to move
132
+
133
+ key_names.each do |key_name|
134
+ # Get old data
135
+ orig_path = [ *orig_keys_path, key_name ]
136
+ data = get_data(request, orig_path, :data_store_exceptions)
137
+
138
+ # Copy data to new path
139
+ create_data(
140
+ request,
141
+ new_keys_path, key_name,
142
+ data,
143
+ :create_dir
144
+ )
145
+ end
146
+
147
+ # Delete original data
148
+ delete_data_dir(request, orig_keys_path, :recursive, :data_store_exceptions)
149
+ end
150
+
151
+ def delete_actor_keys!(request)
152
+ path = keys_path_base(request)[0..-2]
153
+ delete_data_dir(request, path, :recursive, :data_store_exceptions)
154
+ rescue DataStore::DataNotFoundError
155
+ end
156
+
157
+ def client?(request, rest_path = nil)
158
+ rest_path ||= request.rest_path
159
+ rest_path[2] == "clients"
160
+ end
161
+
162
+ # Return the data store keys path for the request client or user, e.g.
163
+ #
164
+ # /organizations/ORG/clients/CLIENT -> /organizations/ORG/client_keys/CLIENT/keys
165
+ # /organizations/ORG/users/USER -> /organizations/ORG/user_keys/USER/keys
166
+ # /users/USER -> /user_keys/USER
167
+ #
168
+ def keys_path_base(request, client_or_user_name = nil)
169
+ rest_path = (rest_path || request.rest_path).dup
170
+ rest_path = rest_path.dup
171
+ case rest_path[-2]
172
+ when "users"
173
+ rest_path[-2] = "user_keys"
174
+ when "clients"
175
+ rest_path[-2] = "client_keys"
176
+ else
177
+ raise "Unexpected URL #{rest_path.join("/")}: cannot determine key path"
178
+ end
179
+ rest_path << "keys"
180
+ rest_path
181
+ end
182
+ end
183
+ end
184
+ end