Merge branch '2873-permission-links-ownership'
authorTim Pierce <twp@curoverse.com>
Thu, 3 Jul 2014 15:45:47 +0000 (11:45 -0400)
committerTim Pierce <twp@curoverse.com>
Thu, 3 Jul 2014 15:45:47 +0000 (11:45 -0400)
Closes #2873. Huzzah!

1  2 
services/api/app/controllers/arvados/v1/links_controller.rb
services/api/app/models/user.rb

index 0772227adca9c0ffa3ac6d541209be8bcf6cecad,722afd13a977fe6b603c71bff11a20e1ff74a11c..f76af60bb93503a3908d48afae6609ff593e9414
@@@ -2,8 -2,7 +2,8 @@@ class Arvados::V1::LinksController < Ap
  
    def check_uuid_kind uuid, kind
      if kind and ArvadosModel::resource_class_for_uuid(uuid).andand.kind != kind
 -      render :json => { errors: ["'#{kind}' does not match uuid '#{uuid}', expected '#{ArvadosModel::resource_class_for_uuid(uuid).andand.kind}'"] }.to_json, status: 422
 +      send_error("'#{kind}' does not match uuid '#{uuid}', expected '#{ArvadosModel::resource_class_for_uuid(uuid).andand.kind}'",
 +                 status: 422)
        nil
      else
        true
      super
    end
  
+   def get_permissions
+     if current_user.can?(manage: @object)
+       # find all links and return them
+       @objects = Link.where(link_class: "permission",
+                             head_uuid: params[:uuid])
+       @offset = 0
+       @limit = @objects.count
+       render_list
+     else
+       render :json => { errors: ['Forbidden'] }.to_json, status: 403
+     end
+   end
    protected
  
+   # Override find_object_by_uuid: the get_permissions method may be
+   # called on a uuid belonging to any class.
+   def find_object_by_uuid
+     if action_name == 'get_permissions'
+       @object = ArvadosModel::resource_class_for_uuid(params[:uuid])
+         .readable_by(*@read_users)
+         .where(uuid: params[:uuid])
+         .first
+     else
+       super
+     end
+   end
    # Overrides ApplicationController load_where_param
    def load_where_param
      super
index 677685d67abdb60270b113ffeb46d6bb5edea81c,2ef56bf7e56754fcc9911a7a67f809115dffbfbd..e79c485f17493cde51cb7bec59c212bb5dc7857e
@@@ -41,11 -41,7 +41,11 @@@ class User < ArvadosMode
    end
  
    def groups_i_can(verb)
 -    self.group_permissions.select { |uuid, mask| mask[verb] }.keys
 +    my_groups = self.group_permissions.select { |uuid, mask| mask[verb] }.keys
 +    if verb == :read
 +      my_groups << anonymous_group_uuid
 +    end
 +    my_groups
    end
  
    def can?(actions)
    # Return a hash of {group_uuid: perm_hash} where perm_hash[:read]
    # and perm_hash[:write] are true if this user can read and write
    # objects owned by group_uuid.
+   #
+   # The permission graph is built by repeatedly enumerating all
+   # permission links reachable from self.uuid, and then calling
+   # search_permissions
    def group_permissions
      Rails.cache.fetch "groups_for_user_#{self.uuid}" do
        permissions_from = {}
        todo = {self.uuid => true}
        done = {}
+       # Build the equivalence class of permissions starting with
+       # self.uuid. On each iteration of this loop, todo contains
+       # the next set of uuids in the permission equivalence class
+       # to evaluate.
        while !todo.empty?
          lookup_uuids = todo.keys
          lookup_uuids.each do |uuid| done[uuid] = true end
          todo = {}
          newgroups = []
+         # include all groups owned by the current set of uuids.
          Group.where('owner_uuid in (?)', lookup_uuids).each do |group|
            newgroups << [group.owner_uuid, group.uuid, 'can_manage']
          end
+         # add any permission links from the current lookup_uuids to a
+         # User or Group.
          Link.where('tail_uuid in (?) and link_class = ? and (head_uuid like ? or head_uuid like ?)',
                     lookup_uuids,
                     'permission',