Next batch of backend permissions for orgs.

This commit is contained in:
yackob03 2013-11-04 15:42:08 -05:00
parent 100ec563fa
commit dd77ebd64f
11 changed files with 13596 additions and 62 deletions

View file

@ -14,6 +14,7 @@ logger = logging.getLogger(__name__)
_ResourceNeed = namedtuple('resource', ['type', 'namespace', 'name', 'role'])
_RepositoryNeed = partial(_ResourceNeed, 'repository')
_OrganizationNeed = namedtuple('organization', ['orgname', 'role'])
class QuayDeferredPermissionUser(Identity):
@ -27,13 +28,27 @@ class QuayDeferredPermissionUser(Identity):
logger.debug('Loading user permissions after deferring.')
user_object = model.get_user(self.id)
for user in model.get_all_user_permissions(user_object):
grant = _RepositoryNeed(user.repositorypermission.repository.namespace,
user.repositorypermission.repository.name,
user.repositorypermission.role.name)
# Add the user specific permissions
user_grant = UserNeed(user_object.username)
self.provides.add(user_grant)
# Every user is the admin of their own 'org'
user_namespace = _OrganizationNeed(user_object.username, 'admin')
self.provides.add(user_namespace)
# Add repository permissions
for perm in model.get_all_user_permissions(user_object):
grant = _RepositoryNeed(perm.repository.namespace,
perm.repository.name, perm.role.name)
logger.debug('User added permission: {0}'.format(grant))
self.provides.add(grant)
# Add namespace permissions derived
for team in model.get_org_wide_permissions(user_object):
grant = _OrganizationNeed(team.organization.username, team.role.name)
logger.debug('Organization team added permission: {0}'.format(grant))
self.provides.add(grant)
self._permissions_loaded = True
return super(QuayDeferredPermissionUser, self).can(permission)
@ -43,6 +58,7 @@ class ModifyRepositoryPermission(Permission):
def __init__(self, namespace, name):
admin_need = _RepositoryNeed(namespace, name, 'admin')
write_need = _RepositoryNeed(namespace, name, 'write')
org_admin_need = _OrganizationNeed(namespace, 'admin')
super(ModifyRepositoryPermission, self).__init__(admin_need, write_need)
@ -51,14 +67,25 @@ class ReadRepositoryPermission(Permission):
admin_need = _RepositoryNeed(namespace, name, 'admin')
write_need = _RepositoryNeed(namespace, name, 'write')
read_need = _RepositoryNeed(namespace, name, 'read')
org_admin_need = _OrganizationNeed(namespace, 'admin')
super(ReadRepositoryPermission, self).__init__(admin_need, write_need,
read_need)
read_need, org_admin_need)
class AdministerRepositoryPermission(Permission):
def __init__(self, namespace, name):
admin_need = _RepositoryNeed(namespace, name, 'admin')
super(AdministerRepositoryPermission, self).__init__(admin_need)
org_admin_need = _OrganizationNeed(namespace, 'admin')
super(AdministerRepositoryPermission, self).__init__(admin_need,
org_admin_need)
class CreateRepositoryPermission(Permission):
def __init__(self, namespace):
admin_org = _OrganizationNeed(namespace, 'admin')
create_repo_org = _OrganizationNeed(namespace, 'creator')
super(CreateRepositoryPermission, self).__init__(admin_org,
create_repo_org)
class UserPermission(Permission):

View file

@ -37,9 +37,14 @@ class User(BaseModel):
organization = BooleanField(default=False, index=True)
class TeamRole(BaseModel):
name = CharField(index=True)
class Team(BaseModel):
name = CharField(index=True)
organization = ForeignKeyField(User, index=True)
role = ForeignKeyField(TeamRole)
class Meta:
database = db
@ -117,18 +122,6 @@ class RepositoryPermission(BaseModel):
)
class TeamPermission(BaseModel):
team = ForeignKeyField(Team, index=True)
organization = ForeignKeyField(User, index=True)
role = ForeignKeyField(Role)
class Meta:
database = db
indexes = (
(('team', 'organization'), True),
)
def random_string_generator(length=16):
def random_string():
random = SystemRandom()
@ -212,10 +205,13 @@ def initialize_db():
RepositoryPermission, Visibility, RepositoryTag,
EmailConfirmation, FederatedLogin, LoginService,
QueueItem, RepositoryBuild, Team, TeamMember,
TeamPermission])
TeamRole])
Role.create(name='admin')
Role.create(name='write')
Role.create(name='read')
TeamRole.create(name='admin')
TeamRole.create(name='creator')
TeamRole.create(name='member')
Visibility.create(name='public')
Visibility.create(name='private')
LoginService.create(name='github')

View file

@ -89,20 +89,17 @@ def create_organization(name, email, creating_user):
new_org.save()
# Create a team for the owners
owners_team = create_team('Owners', new_org)
owners_team = create_team('Owners', new_org, 'admin')
# Add the user who created the org to the owners
# Add the user who created the org to the owners team
add_user_to_team(creating_user, owners_team)
# Give the owners team admin access to the namespace
set_team_org_permission(owners_team, new_org, 'admin')
return new_org
except InvalidUsernameException:
raise InvalidOrganizationException('Invalid organization name: %s' % name)
def create_team(name, org):
def create_team(name, org, team_role_name):
if not validate_username(name):
raise InvalidTeamException('Invalid team name: %s' % name)
@ -110,27 +107,19 @@ def create_team(name, org):
raise InvalidOrganizationException('User with name %s is not an org.' %
org.username)
return Team.create(name=name, organization=org)
team_role = TeamRole.get(TeamRole.name == team_role_name)
return Team.create(name=name, organization=org, role=team_role)
def add_user_to_team(user, team):
return TeamMember.create(user=user, team=team)
def set_team_org_permission(team, org, role_name):
new_role = Role.get(Role.name == role_name)
# Fetch any existing permission for this user on the repo
try:
perm = TeamPermission.get(TeamPermission.team == team,
TeamPermission.organization == org)
perm.role = new_role
perm.save()
return perm
except TeamPermission.DoesNotExist:
new_perm = TeamPermission.create(team=team, organization=org,
role=new_role)
return new_perm
def set_team_org_permission(team, org, team_role_name):
new_role = TeamRole.get(TeamRole.name == tean_role_name)
team.role = new_role
team.save()
return team
def create_federated_user(username, email, service_name, service_id):
@ -327,10 +316,31 @@ def update_email(user, new_email):
def get_all_user_permissions(user):
select = User.select(User, Repository, RepositoryPermission, Role)
with_repo = select.join(RepositoryPermission).join(Repository)
with_role = with_repo.switch(RepositoryPermission).join(Role)
return with_role.where(User.username == user.username)
select = RepositoryPermission.select(RepositoryPermission, Role, Repository)
with_role = select.join(Role)
with_repo = with_role.switch(RepositoryPermission).join(Repository)
through_user = with_repo.switch(RepositoryPermission).join(User,
JOIN_LEFT_OUTER)
as_perm = through_user.switch(RepositoryPermission)
through_team = as_perm.join(Team, JOIN_LEFT_OUTER).join(TeamMember,
JOIN_LEFT_OUTER)
UserThroughTeam = User.alias()
with_team_member = through_team.join(UserThroughTeam, JOIN_LEFT_OUTER,
on=(UserThroughTeam.id ==
TeamMember.user))
return with_team_member.where((User.id == user) |
(UserThroughTeam.id == user))
def get_org_wide_permissions(user):
Org = User.alias()
team_with_role = Team.select(Team, Org, TeamRole).join(TeamRole)
with_org = team_with_role.switch(Team).join(Org, on=(Team.organization ==
Org.id))
with_user = with_org.switch(Team).join(TeamMember).join(User)
return with_user.where(User.id == user, Org.organization == True)
def get_all_repo_teams(namespace_name, repository_name):

View file

@ -23,7 +23,8 @@ from util.names import parse_repository_name
from util.gravatar import compute_hash
from auth.permissions import (ReadRepositoryPermission,
ModifyRepositoryPermission,
AdministerRepositoryPermission)
AdministerRepositoryPermission,
CreateRepositoryPermission)
from endpoints import registry
from endpoints.web import common_login
from util.cache import cache_control
@ -290,22 +291,25 @@ def get_organization_private_allowed(orgname):
@api_login_required
def create_repo_api():
owner = current_user.db_user()
# TODO(jake): Verify that the user can create a repo in this namespace.
json = request.get_json()
namespace_name = json['namespace'] if 'namespace' in json else owner.username
repository_name = json['repository']
visibility = json['visibility']
repo = model.create_repository(namespace_name, repository_name, owner,
visibility)
repo.description = json['description']
repo.save()
permission = CreateRepositoryPermission(json['namespace'])
if permission.can():
namespace_name = json['namespace'] if 'namespace' in json else owner.username
repository_name = json['repository']
visibility = json['visibility']
return jsonify({
'namespace': namespace_name,
'name': repository_name
})
repo = model.create_repository(namespace_name, repository_name, owner,
visibility)
repo.description = json['description']
repo.save()
return jsonify({
'namespace': namespace_name,
'name': repository_name
})
abort(403)
@app.route('/api/find/repository', methods=['GET'])

View file

@ -13,8 +13,9 @@ from auth.auth import (process_auth, get_authenticated_user,
get_validated_token)
from util.names import parse_namespace_repository, parse_repository_name
from util.email import send_confirmation_email
from auth.permissions import (ModifyRepositoryPermission,
ReadRepositoryPermission, UserPermission)
from auth.permissions import (ModifyRepositoryPermission, UserPermission,
ReadRepositoryPermission,
CreateRepositoryPermission)
logger = logging.getLogger(__name__)
@ -127,7 +128,9 @@ def create_repository(namespace, repository):
abort(403)
else:
if get_authenticated_user().username != namespace:
permission = CreateRepoPermission('namespace')
if not permission.can():
logger.info('Attempt to create a new repo with insufficient perms.')
abort(403)
logger.debug('Creaing repository with owner: %s' %

View file

@ -156,7 +156,7 @@ if __name__ == '__main__':
'Repository owned by an org.', False,
[], (4, [], ['latest', 'prod']))
reader_team = model.create_team('Readers', org)
reader_team = model.create_team('Readers', org, 'member')
model.set_team_repo_permission(reader_team.name, org_repo.namespace,
org_repo.name, 'read')
model.add_user_to_team(new_user_2, reader_team)

View file

@ -0,0 +1,45 @@
{
"removed": [],
"added": [
"/opt/elasticsearch-0.90.5/LICENSE.txt",
"/opt/elasticsearch-0.90.5/NOTICE.txt",
"/opt/elasticsearch-0.90.5/README.textile",
"/opt/elasticsearch-0.90.5/bin/elasticsearch",
"/opt/elasticsearch-0.90.5/bin/elasticsearch.in.sh",
"/opt/elasticsearch-0.90.5/bin/plugin",
"/opt/elasticsearch-0.90.5/config/elasticsearch.yml",
"/opt/elasticsearch-0.90.5/config/logging.yml",
"/opt/elasticsearch-0.90.5/lib/elasticsearch-0.90.5.jar",
"/opt/elasticsearch-0.90.5/lib/jna-3.3.0.jar",
"/opt/elasticsearch-0.90.5/lib/jts-1.12.jar",
"/opt/elasticsearch-0.90.5/lib/log4j-1.2.17.jar",
"/opt/elasticsearch-0.90.5/lib/lucene-analyzers-common-4.4.0.jar",
"/opt/elasticsearch-0.90.5/lib/lucene-codecs-4.4.0.jar",
"/opt/elasticsearch-0.90.5/lib/lucene-core-4.4.0.jar",
"/opt/elasticsearch-0.90.5/lib/lucene-grouping-4.4.0.jar",
"/opt/elasticsearch-0.90.5/lib/lucene-highlighter-4.4.0.jar",
"/opt/elasticsearch-0.90.5/lib/lucene-join-4.4.0.jar",
"/opt/elasticsearch-0.90.5/lib/lucene-memory-4.4.0.jar",
"/opt/elasticsearch-0.90.5/lib/lucene-misc-4.4.0.jar",
"/opt/elasticsearch-0.90.5/lib/lucene-queries-4.4.0.jar",
"/opt/elasticsearch-0.90.5/lib/lucene-queryparser-4.4.0.jar",
"/opt/elasticsearch-0.90.5/lib/lucene-sandbox-4.4.0.jar",
"/opt/elasticsearch-0.90.5/lib/lucene-spatial-4.4.0.jar",
"/opt/elasticsearch-0.90.5/lib/lucene-suggest-4.4.0.jar",
"/opt/elasticsearch-0.90.5/lib/sigar/libsigar-amd64-freebsd-6.so",
"/opt/elasticsearch-0.90.5/lib/sigar/libsigar-amd64-linux.so",
"/opt/elasticsearch-0.90.5/lib/sigar/libsigar-amd64-solaris.so",
"/opt/elasticsearch-0.90.5/lib/sigar/libsigar-ia64-linux.so",
"/opt/elasticsearch-0.90.5/lib/sigar/libsigar-sparc-solaris.so",
"/opt/elasticsearch-0.90.5/lib/sigar/libsigar-sparc64-solaris.so",
"/opt/elasticsearch-0.90.5/lib/sigar/libsigar-universal-macosx.dylib",
"/opt/elasticsearch-0.90.5/lib/sigar/libsigar-universal64-macosx.dylib",
"/opt/elasticsearch-0.90.5/lib/sigar/libsigar-x86-freebsd-5.so",
"/opt/elasticsearch-0.90.5/lib/sigar/libsigar-x86-freebsd-6.so",
"/opt/elasticsearch-0.90.5/lib/sigar/libsigar-x86-linux.so",
"/opt/elasticsearch-0.90.5/lib/sigar/libsigar-x86-solaris.so",
"/opt/elasticsearch-0.90.5/lib/sigar/sigar-1.6.4.jar",
"/opt/elasticsearch-0.90.5/lib/spatial4j-0.3.jar"
],
"changed": []
}

View file

@ -0,0 +1,5 @@
{
"removed": [],
"added": [],
"changed": []
}

Binary file not shown.