1 class Arvados::V1::RepositoriesController < ApplicationController
2 skip_before_filter :find_object_by_uuid, :only => :get_all_permissions
3 skip_before_filter :render_404_if_no_object, :only => :get_all_permissions
4 before_filter :admin_required, :only => :get_all_permissions
6 def get_all_permissions
7 # user_aks is a map of {user_uuid => array of public keys}
9 # admins is an array of user_uuids
12 where('users.is_active = ? or users.uuid = ?', true, anonymous_user_uuid).
13 eager_load(:authorized_keys).find_each do |u|
14 user_aks[u.uuid] = u.authorized_keys.collect do |ak|
16 public_key: ak.public_key,
17 authorized_key_uuid: ak.uuid
20 admins << u.uuid if u.is_admin
22 all_group_permissions = User.all_group_permissions
24 Repository.eager_load(:permissions).find_each do |repo|
25 @repo_info[repo.uuid] = {
28 push_url: repo.push_url,
29 fetch_url: repo.fetch_url,
32 # evidence is an array of {name: 'can_xxx', user_uuid: 'x-y-z'},
33 # one entry for each piece of evidence we find in the permission
34 # database that establishes that a user can access this
35 # repository. Multiple entries can be added for a given user,
36 # possibly with different access levels; these will be compacted
39 repo.permissions.each do |perm|
40 if ArvadosModel::resource_class_for_uuid(perm.tail_uuid) == Group
41 # A group has permission. Each user who has access to this
42 # group also has access to the repository. Access level is
43 # min(group-to-repo permission, user-to-group permission).
44 user_aks.each do |user_uuid, _|
45 perm_mask = all_group_permissions[user_uuid][perm.tail_uuid]
48 elsif perm_mask[:manage] and perm.name == 'can_manage'
49 evidence << {name: 'can_manage', user_uuid: user_uuid}
50 elsif perm_mask[:write] and ['can_manage', 'can_write'].index perm.name
51 evidence << {name: 'can_write', user_uuid: user_uuid}
52 elsif perm_mask[:read]
53 evidence << {name: 'can_read', user_uuid: user_uuid}
56 elsif user_aks.has_key?(perm.tail_uuid)
57 # A user has permission; the user exists; and either the
58 # user is active, or it's the special case of the anonymous
59 # user which is never "active" but is allowed to read
60 # content from public repositories.
61 evidence << {name: perm.name, user_uuid: perm.tail_uuid}
64 # Owner of the repository, and all admins, can do everything.
65 ([repo.owner_uuid] | admins).each do |user_uuid|
66 # Except: no permissions for inactive users, even if they own
68 next unless user_aks.has_key?(user_uuid)
69 evidence << {name: 'can_manage', user_uuid: user_uuid}
71 # Distill all the evidence about permissions on this repository
72 # into one hash per user, of the form {'can_xxx' => true, ...}.
73 # The hash is nil for a user who has no permissions at all on
74 # this particular repository.
75 evidence.each do |perm|
76 user_uuid = perm[:user_uuid]
77 user_perms = (@repo_info[repo.uuid][:user_permissions][user_uuid] ||= {})
78 user_perms[perm[:name]] = true
81 # Revisit each {'can_xxx' => true, ...} hash for some final
82 # cleanup to make life easier for the requestor.
84 # Add a 'gitolite_permissions' key alongside the 'can_xxx' keys,
85 # for the convenience of the gitolite config file generator.
87 # Add all lesser permissions when a greater permission is
88 # present. If the requestor only wants to know who can write, it
89 # only has to test for 'can_write' in the response.
90 @repo_info.values.each do |repo|
91 repo[:user_permissions].each do |user_uuid, user_perms|
92 if user_perms['can_manage']
93 user_perms['gitolite_permissions'] = 'RW+'
94 user_perms['can_write'] = true
95 user_perms['can_read'] = true
96 elsif user_perms['can_write']
97 user_perms['gitolite_permissions'] = 'RW+'
98 user_perms['can_read'] = true
99 elsif user_perms['can_read']
100 user_perms['gitolite_permissions'] = 'R'
104 # The response looks like
106 # "repositories":[r1,r2,r3,...],
107 # "user_keys":usermap}
108 # where each of r1,r2,r3 looks like
109 # {"uuid":"repo-uuid-1",
110 # "name":"username/reponame",
112 # "user_permissions":{"user-uuid-a":{"can_read":true,"gitolite_permissions":"R"}}}
113 # and usermap looks like
114 # {"user-uuid-a":[{"public_key":"ssh-rsa g...","authorized_key_uuid":"ak-uuid-g"},...],
115 # "user-uuid-b":[{"public_key":"ssh-rsa h...","authorized_key_uuid":"ak-uuid-h"},...],...}
116 send_json(kind: 'arvados#RepositoryPermissionSnapshot',
117 repositories: @repo_info.values,