From 2eb7ff24428d263946505fe7a82853e6211a0e4d Mon Sep 17 00:00:00 2001 From: yackob03 Date: Mon, 4 Nov 2013 16:18:40 -0500 Subject: [PATCH] Add a bunch of the missing permissions from the API. --- auth/permissions.py | 30 +++++++++ endpoints/api.py | 153 ++++++++++++++++++++++++-------------------- 2 files changed, 112 insertions(+), 71 deletions(-) diff --git a/auth/permissions.py b/auth/permissions.py index 3f8e5ea11..b95138d08 100644 --- a/auth/permissions.py +++ b/auth/permissions.py @@ -15,6 +15,7 @@ logger = logging.getLogger(__name__) _ResourceNeed = namedtuple('resource', ['type', 'namespace', 'name', 'role']) _RepositoryNeed = partial(_ResourceNeed, 'repository') _OrganizationNeed = namedtuple('organization', ['orgname', 'role']) +_TeamNeed = namedtuple('orgteam', ['orgname', 'teamname', 'role']) class QuayDeferredPermissionUser(Identity): @@ -49,6 +50,11 @@ class QuayDeferredPermissionUser(Identity): logger.debug('Organization team added permission: {0}'.format(grant)) self.provides.add(grant) + team_grant = _TeamNeed(team.organization.username, team.name, + team.role.name) + logger.debug('Team added permission: {0}'.format(team_grant)) + self.provides.add(team_grant) + self._permissions_loaded = True return super(QuayDeferredPermissionUser, self).can(permission) @@ -94,6 +100,30 @@ class UserPermission(Permission): super(UserPermission, self).__init__(user_need) +class AdministerOrganizationPermission(Permission): + def __init__(self, org_name): + admin_org = _OrganizationNeed(org_name, 'admin') + super(AdministerOrganizationPermission, self).__init__(admin_org) + + +class OrganizationMemberPermission(Permission): + def __init__(self, org_name): + admin_org = _OrganizationNeed(org_name, 'admin') + repo_creator_org = _OrganizationNeed(org_name, 'creator') + org_member = _OrganizationNeed(org_name, 'member') + super(OrganizationMemberPermission, self).__init__(admin_org, org_member, + repo_creator_org) + + +class ViewTeamPermission(Permission): + def __init__(self, org_name, team_name): + team_admin = _TeamNeed(org_name, team_name, 'admin') + team_creator = _TeamNeed(org_name, 'creator') + team_member = _TeamNeed(org_name, 'member') + super(ViewTeamPermission, self).__init__(team_admin, team_creator, + team_member) + + @identity_loaded.connect_via(app) def on_identity_loaded(sender, identity): logger.debug('Identity loaded: %s' % identity) diff --git a/endpoints/api.py b/endpoints/api.py index 316c6fb40..01d0bcb48 100644 --- a/endpoints/api.py +++ b/endpoints/api.py @@ -24,7 +24,9 @@ from util.gravatar import compute_hash from auth.permissions import (ReadRepositoryPermission, ModifyRepositoryPermission, AdministerRepositoryPermission, - CreateRepositoryPermission) + CreateRepositoryPermission, + AdministerOrganizationPermission, + OrganizationMemberPermission) from endpoints import registry from endpoints.web import common_login from util.cache import cache_control @@ -58,11 +60,11 @@ def plans_list(): @app.route('/api/user/', methods=['GET']) def get_logged_in_user(): def org_view(o): - # TODO: return whether the user is really the admin of the organization + admin_org = AdministerOrganizationPermission(o.username) return { 'name': o.username, 'gravatar': compute_hash(o.email), - 'is_org_admin': True + 'is_org_admin': admin_org.can() } if current_user.is_anonymous(): @@ -235,6 +237,7 @@ user_files = UserRequestFiles(app.config['AWS_ACCESS_KEY'], app.config['AWS_SECRET_KEY'], app.config['REGISTRY_S3_BUCKET']) + @app.route('/api/organization/', methods=['GET']) def get_organization(orgname): def team_view(t): @@ -294,80 +297,81 @@ def member_view(m): 'username': m.username } -@app.route('/api/organization//team//members', methods=['GET']) +@app.route('/api/organization//team//members', + methods=['GET']) def get_organization_team_members(orgname, teamname): - if current_user.is_anonymous(): - abort(404) + permission = ViewTeamPermission(orgname, teamname) + if permission.can(): + user = current_user.db_user() + team = None - # TODO: determine whether the user has permission to view the team members of this team - # (i.e. they are a member of the team [maybe??] OR they are an admin of the org) - user = current_user.db_user() - team = None + try: + team = model.get_organization_team(orgname, teamname) + except: + abort(404) + + members = model.get_organization_team_members(team.id) + return jsonify({ + 'members': { m.username : member_view(m) for m in members } + }) - try: - team = model.get_organization_team(orgname, teamname) - except: - abort(404) - - members = model.get_organization_team_members(team.id) - return jsonify({ - 'members': { m.username : member_view(m) for m in members } - }) + abort(403) -@app.route('/api/organization//team//members/', methods=['PUT', 'POST']) +@app.route('/api/organization//team//members/', + methods=['PUT', 'POST']) def update_organization_team_member(orgname, teamname, membername): - if current_user.is_anonymous(): - abort(404) + permission = AdministerOrganizationPermission(orgname) + if permission.can(): + team = None + user = None - # TODO: determine whether the user has permission to put this user as a member of the team. - team = None - user = None + # Find the team. + try: + team = model.get_organization_team(orgname, teamname) + except: + abort(404) - # Find the team. - try: - team = model.get_organization_team(orgname, teamname) - except: - abort(404) + # Find the user. + user = model.get_user(membername) + if not user: + abort(400) + + # Add the user to the team. + model.add_user_to_team(user, team) - # Find the user. - user = model.get_user(membername) - if not user: - abort(400) - - # Add the user to the team. - model.add_user_to_team(user, team) + return jsonify(member_view(user)) - return jsonify(member_view(user)) + abort(403) -@app.route('/api/organization//team//members/', methods=['DELETE']) +@app.route('/api/organization//team//members/', + methods=['DELETE']) def delete_organization_team_member(orgname, teamname, membername): - if current_user.is_anonymous(): - abort(404) + permission = AdministerOrganizationPermission(orgname) + if permission.can(): + team = None + user = None - # TODO: determine whether the user has permission to delete this user as a member of the team. - team = None - user = None + # Find the team. + try: + team = model.get_organization_team(orgname, teamname) + except: + abort(404) - # Find the team. - try: - team = model.get_organization_team(orgname, teamname) - except: - abort(404) + # Find the user. + user = model.get_user(membername) + if not user: + abort(400) + + # Remote the user from the team. + model.remove_user_from_team(user, team) - # Find the user. - user = model.get_user(membername) - if not user: - abort(400) - - # Remote the user from the team. - model.remove_user_from_team(user, team) - - return jsonify({ - 'success': True - }) + return jsonify({ + 'success': True + }) + abort(403) @app.route('/api/repository', methods=['POST']) @@ -648,11 +652,10 @@ def request_repo_build(namespace, repository): abort(403) # Permissions denied -def role_view(repo_perm_obj, username=None): - # TODO: Determine whether the user (if given) is outside of the organization. +def role_view(repo_perm_obj, org_member): return { 'role': repo_perm_obj.role.name, - 'outside_org': username != 'devtable' + 'outside_org': org_member } @@ -733,32 +736,36 @@ def list_tag_images(namespace, repository, tag): abort(403) # Permission denied -@app.route('/api/repository//permissions/team/', methods=['GET']) +@app.route('/api/repository//permissions/team/', + methods=['GET']) @api_login_required @parse_repository_name def list_repo_team_permissions(namespace, repository): permission = AdministerRepositoryPermission(namespace, repository) if permission.can(): repo_perms = model.get_all_repo_teams(namespace, repository) + org_member = OrganizationMemberPermission(namespace).can() return jsonify({ - 'permissions': {repo_perm.team.name: role_view(repo_perm) + 'permissions': {repo_perm.team.name: role_view(repo_perm, org_member) for repo_perm in repo_perms} }) abort(403) # Permission denied -@app.route('/api/repository//permissions/user/', methods=['GET']) +@app.route('/api/repository//permissions/user/', + methods=['GET']) @api_login_required @parse_repository_name def list_repo_user_permissions(namespace, repository): permission = AdministerRepositoryPermission(namespace, repository) if permission.can(): repo_perms = model.get_all_repo_users(namespace, repository) + member = OrganizationMemberPermission(namespace).can() return jsonify({ - 'permissions': {repo_perm.user.username: role_view(repo_perm, username=repo_perm.user.username) + 'permissions': {repo_perm.user.username: role_view(repo_perm, member) for repo_perm in repo_perms} }) @@ -775,7 +782,8 @@ def get_user_permissions(namespace, repository, username): permission = AdministerRepositoryPermission(namespace, repository) if permission.can(): perm = model.get_user_reponame_permission(username, namespace, repository) - return jsonify(role_view(perm, username=username)) + org_member = OrganizationMemberPermission(namespace).can() + return jsonify(role_view(perm, org_member)) abort(403) # Permission denied @@ -790,7 +798,8 @@ def get_team_permissions(namespace, repository, teamname): permission = AdministerRepositoryPermission(namespace, repository) if permission.can(): perm = model.get_team_reponame_permission(username, namespace, repository) - return jsonify(role_view(perm)) + org_member = OrganizationMemberPermission(namespace).can() + return jsonify(role_view(perm, org_member)) abort(403) # Permission denied @@ -814,7 +823,8 @@ def change_user_permissions(namespace, repository, username): logger.warning('User tried to remove themselves as admin.') abort(409) - resp = jsonify(role_view(perm, username=username)) + org_member = OrganizationMemberPermission(namespace).can() + resp = jsonify(role_view(perm, org_member)) if request.method == 'POST': resp.status_code = 201 return resp @@ -841,7 +851,8 @@ def change_team_permissions(namespace, repository, teamname): logger.warning('User tried to remove themselves as admin.') abort(409) - resp = jsonify(role_view(perm)) + org_member = OrganizationMemberPermission(namespace).can() + resp = jsonify(role_view(perm, org_member)) if request.method == 'POST': resp.status_code = 201 return resp