Add a bunch of the missing permissions from the API.
This commit is contained in:
parent
3698e494a1
commit
2eb7ff2442
2 changed files with 112 additions and 71 deletions
|
@ -15,6 +15,7 @@ logger = logging.getLogger(__name__)
|
||||||
_ResourceNeed = namedtuple('resource', ['type', 'namespace', 'name', 'role'])
|
_ResourceNeed = namedtuple('resource', ['type', 'namespace', 'name', 'role'])
|
||||||
_RepositoryNeed = partial(_ResourceNeed, 'repository')
|
_RepositoryNeed = partial(_ResourceNeed, 'repository')
|
||||||
_OrganizationNeed = namedtuple('organization', ['orgname', 'role'])
|
_OrganizationNeed = namedtuple('organization', ['orgname', 'role'])
|
||||||
|
_TeamNeed = namedtuple('orgteam', ['orgname', 'teamname', 'role'])
|
||||||
|
|
||||||
|
|
||||||
class QuayDeferredPermissionUser(Identity):
|
class QuayDeferredPermissionUser(Identity):
|
||||||
|
@ -49,6 +50,11 @@ class QuayDeferredPermissionUser(Identity):
|
||||||
logger.debug('Organization team added permission: {0}'.format(grant))
|
logger.debug('Organization team added permission: {0}'.format(grant))
|
||||||
self.provides.add(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
|
self._permissions_loaded = True
|
||||||
|
|
||||||
return super(QuayDeferredPermissionUser, self).can(permission)
|
return super(QuayDeferredPermissionUser, self).can(permission)
|
||||||
|
@ -94,6 +100,30 @@ class UserPermission(Permission):
|
||||||
super(UserPermission, self).__init__(user_need)
|
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)
|
@identity_loaded.connect_via(app)
|
||||||
def on_identity_loaded(sender, identity):
|
def on_identity_loaded(sender, identity):
|
||||||
logger.debug('Identity loaded: %s' % identity)
|
logger.debug('Identity loaded: %s' % identity)
|
||||||
|
|
153
endpoints/api.py
153
endpoints/api.py
|
@ -24,7 +24,9 @@ from util.gravatar import compute_hash
|
||||||
from auth.permissions import (ReadRepositoryPermission,
|
from auth.permissions import (ReadRepositoryPermission,
|
||||||
ModifyRepositoryPermission,
|
ModifyRepositoryPermission,
|
||||||
AdministerRepositoryPermission,
|
AdministerRepositoryPermission,
|
||||||
CreateRepositoryPermission)
|
CreateRepositoryPermission,
|
||||||
|
AdministerOrganizationPermission,
|
||||||
|
OrganizationMemberPermission)
|
||||||
from endpoints import registry
|
from endpoints import registry
|
||||||
from endpoints.web import common_login
|
from endpoints.web import common_login
|
||||||
from util.cache import cache_control
|
from util.cache import cache_control
|
||||||
|
@ -58,11 +60,11 @@ def plans_list():
|
||||||
@app.route('/api/user/', methods=['GET'])
|
@app.route('/api/user/', methods=['GET'])
|
||||||
def get_logged_in_user():
|
def get_logged_in_user():
|
||||||
def org_view(o):
|
def org_view(o):
|
||||||
# TODO: return whether the user is really the admin of the organization
|
admin_org = AdministerOrganizationPermission(o.username)
|
||||||
return {
|
return {
|
||||||
'name': o.username,
|
'name': o.username,
|
||||||
'gravatar': compute_hash(o.email),
|
'gravatar': compute_hash(o.email),
|
||||||
'is_org_admin': True
|
'is_org_admin': admin_org.can()
|
||||||
}
|
}
|
||||||
|
|
||||||
if current_user.is_anonymous():
|
if current_user.is_anonymous():
|
||||||
|
@ -235,6 +237,7 @@ user_files = UserRequestFiles(app.config['AWS_ACCESS_KEY'],
|
||||||
app.config['AWS_SECRET_KEY'],
|
app.config['AWS_SECRET_KEY'],
|
||||||
app.config['REGISTRY_S3_BUCKET'])
|
app.config['REGISTRY_S3_BUCKET'])
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/organization/<orgname>', methods=['GET'])
|
@app.route('/api/organization/<orgname>', methods=['GET'])
|
||||||
def get_organization(orgname):
|
def get_organization(orgname):
|
||||||
def team_view(t):
|
def team_view(t):
|
||||||
|
@ -294,80 +297,81 @@ def member_view(m):
|
||||||
'username': m.username
|
'username': m.username
|
||||||
}
|
}
|
||||||
|
|
||||||
@app.route('/api/organization/<orgname>/team/<teamname>/members', methods=['GET'])
|
@app.route('/api/organization/<orgname>/team/<teamname>/members',
|
||||||
|
methods=['GET'])
|
||||||
def get_organization_team_members(orgname, teamname):
|
def get_organization_team_members(orgname, teamname):
|
||||||
if current_user.is_anonymous():
|
permission = ViewTeamPermission(orgname, teamname)
|
||||||
abort(404)
|
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
|
try:
|
||||||
# (i.e. they are a member of the team [maybe??] OR they are an admin of the org)
|
team = model.get_organization_team(orgname, teamname)
|
||||||
user = current_user.db_user()
|
except:
|
||||||
team = None
|
abort(404)
|
||||||
|
|
||||||
|
members = model.get_organization_team_members(team.id)
|
||||||
|
return jsonify({
|
||||||
|
'members': { m.username : member_view(m) for m in members }
|
||||||
|
})
|
||||||
|
|
||||||
try:
|
abort(403)
|
||||||
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 }
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/organization/<orgname>/team/<teamname>/members/<membername>', methods=['PUT', 'POST'])
|
@app.route('/api/organization/<orgname>/team/<teamname>/members/<membername>',
|
||||||
|
methods=['PUT', 'POST'])
|
||||||
def update_organization_team_member(orgname, teamname, membername):
|
def update_organization_team_member(orgname, teamname, membername):
|
||||||
if current_user.is_anonymous():
|
permission = AdministerOrganizationPermission(orgname)
|
||||||
abort(404)
|
if permission.can():
|
||||||
|
team = None
|
||||||
|
user = None
|
||||||
|
|
||||||
# TODO: determine whether the user has permission to put this user as a member of the team.
|
# Find the team.
|
||||||
team = None
|
try:
|
||||||
user = None
|
team = model.get_organization_team(orgname, teamname)
|
||||||
|
except:
|
||||||
|
abort(404)
|
||||||
|
|
||||||
# Find the team.
|
# Find the user.
|
||||||
try:
|
user = model.get_user(membername)
|
||||||
team = model.get_organization_team(orgname, teamname)
|
if not user:
|
||||||
except:
|
abort(400)
|
||||||
abort(404)
|
|
||||||
|
# Add the user to the team.
|
||||||
|
model.add_user_to_team(user, team)
|
||||||
|
|
||||||
# Find the user.
|
return jsonify(member_view(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))
|
abort(403)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/organization/<orgname>/team/<teamname>/members/<membername>', methods=['DELETE'])
|
@app.route('/api/organization/<orgname>/team/<teamname>/members/<membername>',
|
||||||
|
methods=['DELETE'])
|
||||||
def delete_organization_team_member(orgname, teamname, membername):
|
def delete_organization_team_member(orgname, teamname, membername):
|
||||||
if current_user.is_anonymous():
|
permission = AdministerOrganizationPermission(orgname)
|
||||||
abort(404)
|
if permission.can():
|
||||||
|
team = None
|
||||||
|
user = None
|
||||||
|
|
||||||
# TODO: determine whether the user has permission to delete this user as a member of the team.
|
# Find the team.
|
||||||
team = None
|
try:
|
||||||
user = None
|
team = model.get_organization_team(orgname, teamname)
|
||||||
|
except:
|
||||||
|
abort(404)
|
||||||
|
|
||||||
# Find the team.
|
# Find the user.
|
||||||
try:
|
user = model.get_user(membername)
|
||||||
team = model.get_organization_team(orgname, teamname)
|
if not user:
|
||||||
except:
|
abort(400)
|
||||||
abort(404)
|
|
||||||
|
# Remote the user from the team.
|
||||||
|
model.remove_user_from_team(user, team)
|
||||||
|
|
||||||
# Find the user.
|
return jsonify({
|
||||||
user = model.get_user(membername)
|
'success': True
|
||||||
if not user:
|
})
|
||||||
abort(400)
|
|
||||||
|
|
||||||
# Remote the user from the team.
|
|
||||||
model.remove_user_from_team(user, team)
|
|
||||||
|
|
||||||
return jsonify({
|
|
||||||
'success': True
|
|
||||||
})
|
|
||||||
|
|
||||||
|
abort(403)
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/repository', methods=['POST'])
|
@app.route('/api/repository', methods=['POST'])
|
||||||
|
@ -648,11 +652,10 @@ def request_repo_build(namespace, repository):
|
||||||
abort(403) # Permissions denied
|
abort(403) # Permissions denied
|
||||||
|
|
||||||
|
|
||||||
def role_view(repo_perm_obj, username=None):
|
def role_view(repo_perm_obj, org_member):
|
||||||
# TODO: Determine whether the user (if given) is outside of the organization.
|
|
||||||
return {
|
return {
|
||||||
'role': repo_perm_obj.role.name,
|
'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
|
abort(403) # Permission denied
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/repository/<path:repository>/permissions/team/', methods=['GET'])
|
@app.route('/api/repository/<path:repository>/permissions/team/',
|
||||||
|
methods=['GET'])
|
||||||
@api_login_required
|
@api_login_required
|
||||||
@parse_repository_name
|
@parse_repository_name
|
||||||
def list_repo_team_permissions(namespace, repository):
|
def list_repo_team_permissions(namespace, repository):
|
||||||
permission = AdministerRepositoryPermission(namespace, repository)
|
permission = AdministerRepositoryPermission(namespace, repository)
|
||||||
if permission.can():
|
if permission.can():
|
||||||
repo_perms = model.get_all_repo_teams(namespace, repository)
|
repo_perms = model.get_all_repo_teams(namespace, repository)
|
||||||
|
org_member = OrganizationMemberPermission(namespace).can()
|
||||||
|
|
||||||
return jsonify({
|
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}
|
for repo_perm in repo_perms}
|
||||||
})
|
})
|
||||||
|
|
||||||
abort(403) # Permission denied
|
abort(403) # Permission denied
|
||||||
|
|
||||||
|
|
||||||
@app.route('/api/repository/<path:repository>/permissions/user/', methods=['GET'])
|
@app.route('/api/repository/<path:repository>/permissions/user/',
|
||||||
|
methods=['GET'])
|
||||||
@api_login_required
|
@api_login_required
|
||||||
@parse_repository_name
|
@parse_repository_name
|
||||||
def list_repo_user_permissions(namespace, repository):
|
def list_repo_user_permissions(namespace, repository):
|
||||||
permission = AdministerRepositoryPermission(namespace, repository)
|
permission = AdministerRepositoryPermission(namespace, repository)
|
||||||
if permission.can():
|
if permission.can():
|
||||||
repo_perms = model.get_all_repo_users(namespace, repository)
|
repo_perms = model.get_all_repo_users(namespace, repository)
|
||||||
|
member = OrganizationMemberPermission(namespace).can()
|
||||||
|
|
||||||
return jsonify({
|
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}
|
for repo_perm in repo_perms}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -775,7 +782,8 @@ def get_user_permissions(namespace, repository, username):
|
||||||
permission = AdministerRepositoryPermission(namespace, repository)
|
permission = AdministerRepositoryPermission(namespace, repository)
|
||||||
if permission.can():
|
if permission.can():
|
||||||
perm = model.get_user_reponame_permission(username, namespace, repository)
|
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
|
abort(403) # Permission denied
|
||||||
|
|
||||||
|
@ -790,7 +798,8 @@ def get_team_permissions(namespace, repository, teamname):
|
||||||
permission = AdministerRepositoryPermission(namespace, repository)
|
permission = AdministerRepositoryPermission(namespace, repository)
|
||||||
if permission.can():
|
if permission.can():
|
||||||
perm = model.get_team_reponame_permission(username, namespace, repository)
|
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
|
abort(403) # Permission denied
|
||||||
|
|
||||||
|
@ -814,7 +823,8 @@ def change_user_permissions(namespace, repository, username):
|
||||||
logger.warning('User tried to remove themselves as admin.')
|
logger.warning('User tried to remove themselves as admin.')
|
||||||
abort(409)
|
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':
|
if request.method == 'POST':
|
||||||
resp.status_code = 201
|
resp.status_code = 201
|
||||||
return resp
|
return resp
|
||||||
|
@ -841,7 +851,8 @@ def change_team_permissions(namespace, repository, teamname):
|
||||||
logger.warning('User tried to remove themselves as admin.')
|
logger.warning('User tried to remove themselves as admin.')
|
||||||
abort(409)
|
abort(409)
|
||||||
|
|
||||||
resp = jsonify(role_view(perm))
|
org_member = OrganizationMemberPermission(namespace).can()
|
||||||
|
resp = jsonify(role_view(perm, org_member))
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
resp.status_code = 201
|
resp.status_code = 201
|
||||||
return resp
|
return resp
|
||||||
|
|
Reference in a new issue