Add a user info scope and thread it through the code. Protect the org modification API.
This commit is contained in:
parent
89556172d5
commit
64071b9e8e
13 changed files with 144 additions and 115 deletions
|
@ -53,7 +53,8 @@ def process_basic_auth(auth):
|
|||
logger.debug('Successfully validated robot: %s' % credentials[0])
|
||||
set_authenticated_user(robot)
|
||||
|
||||
deferred_robot = QuayDeferredPermissionUser(robot.username, 'username')
|
||||
deferred_robot = QuayDeferredPermissionUser(robot.username, 'username',
|
||||
{'direct_user_login'})
|
||||
identity_changed.send(app, identity=deferred_robot)
|
||||
return
|
||||
except model.InvalidRobotException:
|
||||
|
@ -66,7 +67,8 @@ def process_basic_auth(auth):
|
|||
logger.debug('Successfully validated user: %s' % authenticated.username)
|
||||
set_authenticated_user(authenticated)
|
||||
|
||||
new_identity = QuayDeferredPermissionUser(authenticated.username, 'username')
|
||||
new_identity = QuayDeferredPermissionUser(authenticated.username, 'username',
|
||||
{'direct_user_login'})
|
||||
identity_changed.send(app, identity=new_identity)
|
||||
return
|
||||
|
||||
|
@ -150,7 +152,7 @@ def process_oauth(f):
|
|||
elif not current_user.is_anonymous():
|
||||
logger.debug('Loading user from cookie: %s', current_user.get_id())
|
||||
set_authenticated_user_deferred(current_user.get_id())
|
||||
loaded = QuayDeferredPermissionUser(current_user.get_id(), 'username')
|
||||
loaded = QuayDeferredPermissionUser(current_user.get_id(), 'username', {'direct_user_login'})
|
||||
identity_changed.send(app, identity=loaded)
|
||||
else:
|
||||
logger.debug('No auth header or login cookie.')
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
import logging
|
||||
|
||||
from flask.ext.principal import (identity_loaded, UserNeed, Permission,
|
||||
Identity, identity_changed)
|
||||
from flask.ext.login import current_user
|
||||
from collections import namedtuple
|
||||
from flask.ext.principal import identity_loaded, Permission, Identity, identity_changed
|
||||
from collections import namedtuple, defaultdict
|
||||
from functools import partial
|
||||
|
||||
from data import model
|
||||
|
@ -17,27 +15,36 @@ _ResourceNeed = namedtuple('resource', ['type', 'namespace', 'name', 'role'])
|
|||
_RepositoryNeed = partial(_ResourceNeed, 'repository')
|
||||
_OrganizationNeed = namedtuple('organization', ['orgname', 'role'])
|
||||
_TeamNeed = namedtuple('orgteam', ['orgname', 'teamname', 'role'])
|
||||
_UserNeed = namedtuple('user', ['username', 'role'])
|
||||
|
||||
|
||||
REPO_ROLES = [None, 'read', 'write', 'admin']
|
||||
TEAM_ROLES = [None, 'member', 'creator', 'admin']
|
||||
USER_ROLES = [None, 'read', 'admin']
|
||||
|
||||
SCOPE_MAX_REPO_ROLES = {
|
||||
SCOPE_MAX_REPO_ROLES = defaultdict(lambda: None)
|
||||
SCOPE_MAX_REPO_ROLES.update({
|
||||
'repo:read': 'read',
|
||||
'repo:write': 'write',
|
||||
'repo:admin': 'admin',
|
||||
'repo:create': None,
|
||||
}
|
||||
'direct_user_login': 'admin',
|
||||
})
|
||||
|
||||
SCOPE_MAX_TEAM_ROLES = {
|
||||
'repo:read': None,
|
||||
'repo:write': None,
|
||||
'repo:admin': None,
|
||||
SCOPE_MAX_TEAM_ROLES = defaultdict(lambda: None)
|
||||
SCOPE_MAX_TEAM_ROLES.update({
|
||||
'repo:create': 'creator',
|
||||
}
|
||||
'direct_user_login': 'admin',
|
||||
})
|
||||
|
||||
SCOPE_MAX_USER_ROLES = defaultdict(lambda: None)
|
||||
SCOPE_MAX_USER_ROLES.update({
|
||||
'user:read': 'admin',
|
||||
'direct_user_login': 'admin',
|
||||
})
|
||||
|
||||
|
||||
class QuayDeferredPermissionUser(Identity):
|
||||
def __init__(self, id, auth_type=None, scopes=None):
|
||||
def __init__(self, id, auth_type, scopes):
|
||||
super(QuayDeferredPermissionUser, self).__init__(id, auth_type)
|
||||
|
||||
self._permissions_loaded = False
|
||||
|
@ -61,16 +68,18 @@ class QuayDeferredPermissionUser(Identity):
|
|||
def _repo_role_for_scopes(self, role):
|
||||
return self._translate_role_for_scopes(REPO_ROLES, SCOPE_MAX_REPO_ROLES, role)
|
||||
|
||||
def _user_role_for_scopes(self, role):
|
||||
return self._translate_role_for_scopes(USER_ROLES, SCOPE_MAX_USER_ROLES, role)
|
||||
|
||||
def can(self, permission):
|
||||
if not self._permissions_loaded:
|
||||
logger.debug('Loading user permissions after deferring.')
|
||||
user_object = model.get_user(self.id)
|
||||
|
||||
# Add the user specific permissions, only for non-oauth permission
|
||||
if self._scope_set is None:
|
||||
user_grant = UserNeed(user_object.username)
|
||||
self.provides.add(user_grant)
|
||||
logger.debug('Add admin to user namespace: %s', user_object.username)
|
||||
# Add the user specific permissions, only for non-oauth permission
|
||||
user_grant = _UserNeed(user_object.username, self._user_role_for_scopes('admin'))
|
||||
self.provides.add(user_grant)
|
||||
logger.debug('User permission: {0}'.format(user_grant))
|
||||
|
||||
# Every user is the admin of their own 'org'
|
||||
user_namespace = _OrganizationNeed(user_object.username, self._team_role_for_scopes('admin'))
|
||||
|
@ -135,10 +144,17 @@ class CreateRepositoryPermission(Permission):
|
|||
create_repo_org)
|
||||
|
||||
|
||||
class UserPermission(Permission):
|
||||
class UserAdminPermission(Permission):
|
||||
def __init__(self, username):
|
||||
user_need = UserNeed(username)
|
||||
super(UserPermission, self).__init__(user_need)
|
||||
user_admin = _UserNeed(username, 'admin')
|
||||
super(UserAdminPermission, self).__init__(user_admin)
|
||||
|
||||
|
||||
class UserReadPermission(Permission):
|
||||
def __init__(self, username):
|
||||
user_admin = _UserNeed(username, 'admin')
|
||||
user_read = _UserNeed(username, 'read')
|
||||
super(UserReadPermission, self).__init__(user_read, user_admin)
|
||||
|
||||
|
||||
class AdministerOrganizationPermission(Permission):
|
||||
|
@ -176,7 +192,7 @@ def on_identity_loaded(sender, identity):
|
|||
|
||||
elif identity.auth_type == 'username':
|
||||
logger.debug('Switching username permission to deferred object: %s', identity.id)
|
||||
switch_to_deferred = QuayDeferredPermissionUser(identity.id, 'username')
|
||||
switch_to_deferred = QuayDeferredPermissionUser(identity.id, 'username', {'direct_user_login'})
|
||||
identity_changed.send(app, identity=switch_to_deferred)
|
||||
|
||||
elif identity.auth_type == 'token':
|
||||
|
|
|
@ -10,16 +10,16 @@ WRITE_REPO = {
|
|||
'scope': 'repo:write',
|
||||
'icon': 'fa-hdd-o',
|
||||
'title': 'Read/Write to any accessible repositories',
|
||||
'description': ('This application will be able to view, push and pull to all repositories to which the '
|
||||
'granting user or robot account has write access')
|
||||
'description': ('This application will be able to view, push and pull to all repositories to '
|
||||
'which the granting user or robot account has write access')
|
||||
}
|
||||
|
||||
ADMIN_REPO = {
|
||||
'scope': 'repo:admin',
|
||||
'icon': 'fa-hdd-o',
|
||||
'title': 'Administer Repositories',
|
||||
'description': ('This application will have administrator access to all repositories to which the '
|
||||
'granting user or robot account has access')
|
||||
'description': ('This application will have administrator access to all repositories to which '
|
||||
'the granting user or robot account has access')
|
||||
}
|
||||
|
||||
CREATE_REPO = {
|
||||
|
@ -30,7 +30,16 @@ CREATE_REPO = {
|
|||
'the granting user or robot account is allowed to create repositories')
|
||||
}
|
||||
|
||||
ALL_SCOPES = {scope['scope']:scope for scope in (READ_REPO, WRITE_REPO, ADMIN_REPO, CREATE_REPO)}
|
||||
USER_READ = {
|
||||
'scope': 'user:read',
|
||||
'icon': 'fa-user',
|
||||
'title': 'Read User Information',
|
||||
'description': ('This application will be able to read user information such as username and '
|
||||
'email address.'),
|
||||
}
|
||||
|
||||
ALL_SCOPES = {scope['scope']:scope for scope in (READ_REPO, WRITE_REPO, ADMIN_REPO, CREATE_REPO,
|
||||
USER_READ)}
|
||||
|
||||
|
||||
def scopes_from_scope_string(scopes):
|
||||
|
|
Reference in a new issue