16683: Permit granting permissions to remote users
authorPeter Amstutz <peter.amstutz@curii.com>
Wed, 12 Aug 2020 21:32:06 +0000 (17:32 -0400)
committerPeter Amstutz <peter.amstutz@curii.com>
Thu, 13 Aug 2020 21:27:07 +0000 (17:27 -0400)
Arvados-DCO-1.1-Signed-off-by: Peter Amstutz <peter.amstutz@curii.com>

sdk/go/arvados/api.go
services/api/app/models/arvados_model.rb
services/api/app/models/link.rb

index ec04cececb392fb0ec4b86038be1144287524edc..4695a9504fd9096939e53b3a52fb5c53208fdbab 100644 (file)
@@ -85,7 +85,7 @@ type ListOptions struct {
        IncludeTrash       bool                   `json:"include_trash"`
        IncludeOldVersions bool                   `json:"include_old_versions"`
        BypassFederation   bool                   `json:"bypass_federation"`
-       ForwardedFor string   `json:"forwarded_for,omitempty"`
+       ForwardedFor       string                 `json:"forwarded_for,omitempty"`
 }
 
 type CreateOptions struct {
index 816dbf4758dd0baa6e4ca438434b0b770fd1c0b7..7f6ab462dea3f814539e1ceab3546ae3d98b9446 100644 (file)
@@ -716,6 +716,20 @@ class ArvadosModel < ApplicationRecord
     %r/[a-z0-9]{5}-#{uuid_prefix}-[a-z0-9]{15}/
   end
 
+  def check_readable_uuid attr, attr_value
+    return if attr_value.nil?
+    if (r = ArvadosModel::resource_class_for_uuid attr_value)
+      unless skip_uuid_read_permission_check.include? attr
+        r = r.readable_by(current_user)
+      end
+      if r.where(uuid: attr_value).count == 0
+        errors.add(attr, "'#{attr_value}' not found")
+      end
+    else
+      # Not a valid uuid or PDH, but that (currently) is not an error.
+    end
+  end
+
   def ensure_valid_uuids
     specials = [system_user_uuid]
 
@@ -724,16 +738,7 @@ class ArvadosModel < ApplicationRecord
         next if skip_uuid_existence_check.include? attr
         attr_value = send attr
         next if specials.include? attr_value
-        if attr_value
-          if (r = ArvadosModel::resource_class_for_uuid attr_value)
-            unless skip_uuid_read_permission_check.include? attr
-              r = r.readable_by(current_user)
-            end
-            if r.where(uuid: attr_value).count == 0
-              errors.add(attr, "'#{attr_value}' not found")
-            end
-          end
-        end
+        check_readable_uuid attr, attr_value
       end
     end
   end
index ad7800fe679cb91936bde76f00566873cb369419..c580d63b0157c3ccc76316ba2108533a36c29551 100644 (file)
@@ -42,6 +42,27 @@ class Link < ArvadosModel
 
   protected
 
+  def check_readable_uuid attr, attr_value
+    if attr == 'tail_uuid' &&
+       !attr_value.nil? &&
+       self.link_class == 'permission' &&
+       attr_value[0..4] != Rails.configuration.ClusterID &&
+       ArvadosModel::resource_class_for_uuid(attr_value) == User
+      # Permission link tail is a remote user (the user permissions
+      # are being granted to), so bypass the standard check that a
+      # referenced object uuid is readable by current user.
+      #
+      # We could do a call to the remote cluster to check if the user
+      # in tail_uuid exists.  This would detect copy-and-paste errors,
+      # but add another way for the request to fail, and I don't think
+      # it would improve security.  It doesn't seem to be worth the
+      # complexity tradeoff.
+      true
+    else
+      super
+    end
+  end
+
   def permission_to_attach_to_objects
     # Anonymous users cannot write links
     return false if !current_user
@@ -54,6 +75,11 @@ class Link < ArvadosModel
 
     head_obj = ArvadosModel.find_by_uuid(head_uuid)
 
+    if head_obj.nil?
+      errors.add(:head_uuid, "does not exist")
+      return false
+    end
+
     # No permission links can be pointed to past collection versions
     return false if head_obj.is_a?(Collection) && head_obj.current_version_uuid != head_uuid