diff --git a/auth/permissions.py b/auth/permissions.py index b2e7fe784..2b27f9583 100644 --- a/auth/permissions.py +++ b/auth/permissions.py @@ -47,6 +47,7 @@ SCOPE_MAX_TEAM_ROLES = defaultdict(lambda: None) SCOPE_MAX_TEAM_ROLES.update({ scopes.CREATE_REPO: 'creator', scopes.DIRECT_LOGIN: 'admin', + scopes.ORG_ADMIN: 'admin', }) SCOPE_MAX_USER_ROLES = defaultdict(lambda: None) diff --git a/auth/scopes.py b/auth/scopes.py index aad91182b..6ab4f811a 100644 --- a/auth/scopes.py +++ b/auth/scopes.py @@ -1,17 +1,19 @@ from collections import namedtuple -Scope = namedtuple('scope', ['scope', 'icon', 'title', 'description']) +Scope = namedtuple('scope', ['scope', 'icon', 'dangerous', 'title', 'description']) READ_REPO = Scope(scope='repo:read', icon='fa-hdd-o', + dangerous=False, title='View all visible repositories', description=('This application will be able to view and pull all repositories ' 'visible to the granting user or robot account')) WRITE_REPO = Scope(scope='repo:write', icon='fa-hdd-o', + dangerous=False, 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 ' @@ -19,34 +21,47 @@ WRITE_REPO = Scope(scope='repo:write', ADMIN_REPO = Scope(scope='repo:admin', icon='fa-hdd-o', + dangerous=False, title='Administer Repositories', description=('This application will have administrator access to all ' 'repositories to which the granting user or robot account has ' 'access')) CREATE_REPO = Scope(scope='repo:create', - icon='fa-plus', - title='Create Repositories', - description=('This application will be able to create repositories in to any ' - 'namespaces that the granting user or robot account is allowed to ' - 'create repositories')) + icon='fa-plus', + dangerous=False, + title='Create Repositories', + description=('This application will be able to create repositories in to any ' + 'namespaces that the granting user or robot account is allowed ' + 'to create repositories')) READ_USER = Scope(scope= 'user:read', icon='fa-user', + dangerous=False, title='Read User Information', description=('This application will be able to read user information such as ' 'username and email address.')) +ORG_ADMIN = Scope(scope='org:admin', + icon='fa-exclamation-triangle', + dangerous=True, + title='Administer Organization', + description=('This application will be able to administer your organizations ' + 'including creating robots, creating teams, adjusting team ' + 'membership, and changing billing settings. You should have ' + 'absolute trust in the requesting application before granting this ' + 'permission.')) DIRECT_LOGIN = Scope(scope='direct_user_login', icon='fa-exclamation-triangle', + dangerous=True, title='Full Access', description=('This scope should not be available to OAuth applications. ' 'Never approve a request for this scope!')) ALL_SCOPES = {scope.scope:scope for scope in (READ_REPO, WRITE_REPO, ADMIN_REPO, CREATE_REPO, - READ_USER)} + READ_USER, ORG_ADMIN)} IMPLIED_SCOPES = { ADMIN_REPO: {ADMIN_REPO, WRITE_REPO, READ_REPO}, @@ -54,6 +69,7 @@ IMPLIED_SCOPES = { READ_REPO: {READ_REPO}, CREATE_REPO: {CREATE_REPO}, READ_USER: {READ_USER}, + ORG_ADMIN: {ORG_ADMIN}, None: set(), } diff --git a/endpoints/api/robot.py b/endpoints/api/robot.py index 0961d694e..f25e87dbd 100644 --- a/endpoints/api/robot.py +++ b/endpoints/api/robot.py @@ -1,7 +1,8 @@ from endpoints.api import (resource, nickname, ApiResource, log_action, related_user_resource, - Unauthorized, require_user_admin, internal_only) + Unauthorized, require_user_admin, internal_only, require_scope) from auth.permissions import AdministerOrganizationPermission, OrganizationMemberPermission from auth.auth_context import get_authenticated_user +from auth import scopes from data import model from util.names import format_robot_username @@ -52,10 +53,10 @@ class UserRobot(ApiResource): @resource('/v1/organization//robots') -@internal_only @related_user_resource(UserRobotList) class OrgRobotList(ApiResource): """ Resource for listing an organization's robots. """ + @require_scope(scopes.ORG_ADMIN) @nickname('getOrgRobots') def get(self, orgname): """ List the organization's robots. """ @@ -70,10 +71,10 @@ class OrgRobotList(ApiResource): @resource('/v1/organization//robots/') -@internal_only @related_user_resource(UserRobot) class OrgRobot(ApiResource): """ Resource for managing an organization's robots. """ + @require_scope(scopes.ORG_ADMIN) @nickname('createOrgRobot') def put(self, orgname, robot_shortname): """ Create a new robot in the organization. """ @@ -86,6 +87,7 @@ class OrgRobot(ApiResource): raise Unauthorized() + @require_scope(scopes.ORG_ADMIN) @nickname('deleteOrgRobot') def delete(self, orgname, robot_shortname): """ Delete an existing organization robot. """ diff --git a/endpoints/api/team.py b/endpoints/api/team.py index e82a2bd69..0631cc028 100644 --- a/endpoints/api/team.py +++ b/endpoints/api/team.py @@ -1,9 +1,10 @@ from flask import request from endpoints.api import (resource, nickname, ApiResource, validate_json_request, request_error, - log_action, Unauthorized, NotFound, internal_only) + log_action, Unauthorized, NotFound, internal_only, require_scope) from auth.permissions import AdministerOrganizationPermission, ViewTeamPermission from auth.auth_context import get_authenticated_user +from auth import scopes from data import model @@ -136,9 +137,9 @@ class TeamMemberList(ApiResource): @resource('/v1/organization//team//members/') -@internal_only class TeamMember(ApiResource): """ Resource for managing individual members of a team. """ + @require_scope(scopes.ORG_ADMIN) @nickname('updateOrganizationTeamMember') def put(self, orgname, teamname, membername): """ Add a member to an existing team. """ @@ -165,6 +166,7 @@ class TeamMember(ApiResource): raise Unauthorized() + @require_scope(scopes.ORG_ADMIN) @nickname('deleteOrganizationTeamMember') def delete(self, orgname, teamname, membername): """ Delete an existing member of a team. """