Skip to content

Commit 777f0db

Browse files
authored
Merge pull request opf#16411 from opf/implementation/55975-use-authentication-in-set_permission_command
[#55975] introduced auth strategy for set permissions command
2 parents a96e19f + 031bae9 commit 777f0db

File tree

5 files changed

+44
-202
lines changed

5 files changed

+44
-202
lines changed

Diff for: modules/storages/app/common/storages/peripherals/storage_interaction/nextcloud/set_permissions_command.rb

+36-23
Original file line numberDiff line numberDiff line change
@@ -37,41 +37,53 @@ class SetPermissionsCommand
3737
using ServiceResultRefinements
3838

3939
SUCCESS_XPATH = "/d:multistatus/d:response/d:propstat[d:status[text() = 'HTTP/1.1 200 OK']]/d:prop/nc:acl-list"
40-
def self.call(storage:, path:, permissions:)
41-
new(storage).call(path:, permissions:)
40+
41+
def self.call(storage:, auth_strategy:, path:, permissions:)
42+
new(storage).call(auth_strategy:, path:, permissions:)
4243
end
4344

4445
def initialize(storage)
4546
@storage = storage
46-
@username = storage.username
47-
@password = storage.password
4847
end
4948

50-
def call(path:, permissions:)
51-
if path.blank?
52-
return ServiceResult.failure(errors: StorageError.new(code: :invalid_path))
53-
end
49+
# rubocop:disable Metrics/AbcSize
50+
def call(auth_strategy:, path:, permissions:)
51+
validate_input_data(path).on_failure { return _1 }
5452

55-
with_tagged_logger do
56-
info "Setting permissions #{permissions.inspect} on #{path}"
57-
58-
body = request_xml_body(permissions[:groups], permissions[:users])
59-
# This can raise KeyErrors, we probably should just default to enpty Arrays.
60-
response = OpenProject
61-
.httpx
62-
.basic_auth(@username, @password)
63-
.request(
64-
"PROPPATCH",
65-
UrlBuilder.url(@storage.uri, "remote.php/dav/files", @username, path),
66-
xml: body
67-
)
68-
69-
handle_response(response)
53+
username = Util.origin_user_id(caller: self.class, storage: @storage, auth_strategy:)
54+
.on_failure { return _1 }
55+
.result
56+
57+
Authentication[auth_strategy].call(storage: @storage) do |http|
58+
with_tagged_logger do
59+
info "Setting permissions #{permissions.inspect} on #{path}"
60+
61+
body = request_xml_body(permissions[:groups], permissions[:users])
62+
# This can raise KeyErrors, we probably should just default to empty Arrays.
63+
response = http
64+
.request(
65+
"PROPPATCH",
66+
UrlBuilder.url(@storage.uri, "remote.php/dav/files", username, path),
67+
xml: body
68+
)
69+
70+
handle_response(response)
71+
end
7072
end
7173
end
7274

75+
# rubocop:enable Metrics/AbcSize
76+
7377
private
7478

79+
def validate_input_data(path)
80+
if path.blank?
81+
ServiceResult.failure(errors: StorageError.new(code: :invalid_path))
82+
else
83+
ServiceResult.success
84+
end
85+
end
86+
7587
# rubocop:disable Metrics/AbcSize
7688
def handle_response(response)
7789
error_data = StorageErrorData.new(source: self.class, payload: response)
@@ -125,6 +137,7 @@ def request_xml_body(groups_permissions, users_permissions)
125137
end
126138
end.to_xml
127139
end
140+
128141
# rubocop:enable Metrics/AbcSize
129142
end
130143
end

Diff for: modules/storages/app/common/storages/peripherals/storage_interaction/one_drive/set_permissions_command.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ def delete? = permission_ids.any? && user_ids.empty?
4545
def update? = permission_ids.any? && user_ids.any?
4646
end
4747

48-
def self.call(storage:, path:, permissions:, auth_strategy:)
49-
new(storage).call(path:, permissions:, auth_strategy:)
48+
def self.call(storage:, auth_strategy:, path:, permissions:)
49+
new(storage).call(auth_strategy:, path:, permissions:)
5050
end
5151

5252
def initialize(storage)

Diff for: modules/storages/app/services/storages/nextcloud_group_folder_properties_sync_service.rb

+3-3
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ def set_folders_permissions(remote_admins, project_storage)
146146
}
147147
}
148148

149-
set_permissions.call(storage: @storage, **command_params).on_failure do |service_result|
149+
set_permissions.call(storage: @storage, auth_strategy:, **command_params).on_failure do |service_result|
150150
log_storage_error(service_result.errors, folder:)
151151
add_error(:set_folder_permission, service_result.errors, options: { folder: })
152152
end
@@ -178,7 +178,7 @@ def hide_inactive_folders(remote_folders)
178178
groups: { "#{@storage.group}": NO_PERMISSIONS }
179179
} }
180180

181-
set_permissions.call(storage: @storage, **command_params).on_failure do |service_result|
181+
set_permissions.call(storage: @storage, auth_strategy:, **command_params).on_failure do |service_result|
182182
log_storage_error(service_result.errors, folder: path, context: "hide_folder")
183183
add_error(:hide_inactive_folders, service_result.errors, options: { path: })
184184
end
@@ -263,7 +263,7 @@ def ensure_root_folder_permissions(group_folder, username, group)
263263
}
264264
}
265265

266-
set_permissions.call(storage: @storage, **command_params).on_failure do |service_result|
266+
set_permissions.call(storage: @storage, auth_strategy:, **command_params).on_failure do |service_result|
267267
log_storage_error(service_result.errors, { folder: group_folder })
268268
add_error(:ensure_root_folder_permissions, service_result.errors, options: { group:, username: }).fail!
269269
end

Diff for: modules/storages/app/services/storages/one_drive_managed_folder_sync_service.rb

+3-2
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def apply_permission_to_folders
7979
end
8080

8181
def set_folder_permissions(folder_id, permissions)
82-
set_permissions.call(storage: @storage, path: folder_id, permissions:, auth_strategy:)
82+
set_permissions.call(storage: @storage, auth_strategy:, path: folder_id, permissions:)
8383
end
8484

8585
def ensure_folders_exist(folder_map)
@@ -104,7 +104,7 @@ def hide_inactive_folders(folder_map)
104104
info "Hiding folder with ID #{item_id} as it does not belong to any active project"
105105

106106
# FIXME: Set permissions wont ever fail.
107-
set_permissions.call(storage: @storage, path: item_id, permissions:, auth_strategy:)
107+
set_permissions.call(storage: @storage, auth_strategy:, path: item_id, permissions:)
108108
.on_failure do |service_result|
109109
log_storage_error(service_result.errors, item_id:, context: "hide_folder")
110110
add_error(:hide_inactive_folders, service_result.errors, options: { path: folder_map[item_id] })
@@ -212,6 +212,7 @@ def admin_remote_identities_scope
212212
end
213213

214214
def root_folder = Peripherals::ParentFolder.new("/")
215+
215216
def auth_strategy = userless.call
216217

217218
# @param attribute [Symbol] attribute to which the error will be tied to

Diff for: modules/storages/spec/common/storages/peripherals/registry_spec.rb

-172
Original file line numberDiff line numberDiff line change
@@ -213,178 +213,6 @@
213213
end
214214
end
215215

216-
describe "#set_permissions_command" do
217-
let(:path) { "OpenProject/JediProject" }
218-
let(:permissions) do
219-
{
220-
users: {
221-
OpenProject: 31,
222-
"Obi-Wan": 31,
223-
"Qui-Gon": 31
224-
},
225-
groups: {
226-
OpenProject: 0
227-
}
228-
}
229-
end
230-
231-
let(:expected_request_body) do
232-
<<~XML
233-
<?xml version="1.0"?>
234-
<d:propertyupdate xmlns:d="DAV:" xmlns:nc="http://nextcloud.org/ns">
235-
<d:set>
236-
<d:prop>
237-
<nc:acl-list>
238-
<nc:acl>
239-
<nc:acl-mapping-type>group</nc:acl-mapping-type>
240-
<nc:acl-mapping-id>OpenProject</nc:acl-mapping-id>
241-
<nc:acl-mask>31</nc:acl-mask>
242-
<nc:acl-permissions>0</nc:acl-permissions>
243-
</nc:acl>
244-
<nc:acl>
245-
<nc:acl-mapping-type>user</nc:acl-mapping-type>
246-
<nc:acl-mapping-id>OpenProject</nc:acl-mapping-id>
247-
<nc:acl-mask>31</nc:acl-mask>
248-
<nc:acl-permissions>31</nc:acl-permissions>
249-
</nc:acl>
250-
<nc:acl>
251-
<nc:acl-mapping-type>user</nc:acl-mapping-type>
252-
<nc:acl-mapping-id>Obi-Wan</nc:acl-mapping-id>
253-
<nc:acl-mask>31</nc:acl-mask>
254-
<nc:acl-permissions>31</nc:acl-permissions>
255-
</nc:acl>
256-
<nc:acl>
257-
<nc:acl-mapping-type>user</nc:acl-mapping-type>
258-
<nc:acl-mapping-id>Qui-Gon</nc:acl-mapping-id>
259-
<nc:acl-mask>31</nc:acl-mask>
260-
<nc:acl-permissions>31</nc:acl-permissions>
261-
</nc:acl>
262-
</nc:acl-list>
263-
</d:prop>
264-
</d:set>
265-
</d:propertyupdate>
266-
XML
267-
end
268-
269-
context "with Nextcloud storage type selected" do
270-
context "with outbound request" do
271-
before do
272-
stub_request(:proppatch, "#{url}/remote.php/dav/files/OpenProject/OpenProject/JediProject")
273-
.with(
274-
body: expected_request_body,
275-
headers: {
276-
"Authorization" => "Basic T3BlblByb2plY3Q6T3BlblByb2plY3RTZWN1cmVQYXNzd29yZA=="
277-
}
278-
)
279-
.to_return(expected_response)
280-
end
281-
282-
context "when permissions can be set" do
283-
let(:expected_response_body) do
284-
<<~XML
285-
<?xml version="1.0"?>
286-
<d:multistatus
287-
xmlns:d="DAV:"
288-
xmlns:s="http://sabredav.org/ns"
289-
xmlns:oc="http://owncloud.org/ns"
290-
xmlns:nc="http://nextcloud.org/ns">
291-
<d:response>
292-
<d:href>/remote.php/dav/files/OpenProject/OpenProject/Project%231</d:href>
293-
<d:propstat>
294-
<d:prop>
295-
<nc:acl-list/>
296-
</d:prop>
297-
<d:status>HTTP/1.1 200 OK</d:status>
298-
</d:propstat>
299-
</d:response>
300-
</d:multistatus>
301-
XML
302-
end
303-
let(:expected_response) do
304-
{
305-
status: 207,
306-
body: expected_response_body,
307-
headers: {}
308-
}
309-
end
310-
311-
it "returns success when permissions can be set" do
312-
result = registry.resolve("nextcloud.commands.set_permissions").call(storage:, path:, permissions:)
313-
expect(result).to be_success
314-
end
315-
end
316-
317-
context "when the password is wrong" do
318-
let(:expected_response_body) do
319-
<<~XML
320-
<?xml version="1.0" encoding="utf-8"?>
321-
<d:error
322-
xmlns:d="DAV:"
323-
xmlns:s="http://sabredav.org/ns">
324-
<s:exception>Sabre\DAV\Exception\NotAuthenticated</s:exception>
325-
<s:message>No public access to this resource., No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured, No 'Authorization: Bearer' header found. Either the client didn't send one, or the server is mis-configured, No 'Authorization: Basic' header found. Either the client didn't send one, or the server is misconfigured</s:message>
326-
</d:error>
327-
XML
328-
end
329-
let(:expected_response) do
330-
{
331-
status: 401,
332-
body: expected_response_body,
333-
headers: {}
334-
}
335-
end
336-
337-
it "returns failure" do
338-
result = registry.resolve("nextcloud.commands.set_permissions").call(storage:, path:, permissions:)
339-
expect(result).to be_failure
340-
end
341-
end
342-
343-
context "when the NC control user cannot read(see) the project folder" do
344-
let(:expected_response_body) do
345-
<<~XML
346-
<?xml version="1.0" encoding="utf-8"?>
347-
<d:error
348-
xmlns:d="DAV:"
349-
xmlns:s="http://sabredav.org/ns">
350-
<s:exception>Sabre\DAV\Exception\NotFound</s:exception>
351-
<s:message>File with name /OpenProject/JediProject could not be located</s:message>
352-
</d:error>
353-
XML
354-
end
355-
let(:expected_response) do
356-
{
357-
status: 404,
358-
body: expected_response_body,
359-
headers: {}
360-
}
361-
end
362-
363-
it "returns failure" do
364-
result = registry.resolve("nextcloud.commands.set_permissions").call(storage:, path:, permissions:)
365-
expect(result).to be_failure
366-
end
367-
end
368-
end
369-
370-
context "when forbidden values are given as folder" do
371-
it "raises an ArgumentError on nil" do
372-
result = registry.resolve("nextcloud.commands.set_permissions").call(storage:, path: nil, permissions:)
373-
374-
expect(result).to be_failure
375-
expect(result.errors.code).to eq(:invalid_path)
376-
end
377-
378-
it "returns a :invalid_path Failure on empty string" do
379-
result = registry.resolve("nextcloud.commands.set_permissions").call(storage:, path: "", permissions:)
380-
381-
expect(result).to be_failure
382-
expect(result.errors.code).to eq(:invalid_path)
383-
end
384-
end
385-
end
386-
end
387-
388216
describe "#file_ids_query" do
389217
let(:nextcloud_subpath) { "" }
390218
let(:url) { "https://example.com#{nextcloud_subpath}" }

0 commit comments

Comments
 (0)