This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/endpoints/api/test/test_security.py
Joseph Schorr fc6eb71ab1 Switch from an image view UI to a manifest view UI
We no longer allow viewing individual images, but instead only manifests. This will help with the transition to Clair V3 (which is manifest based) and, eventually, the the new data model (which will also be manifest based)
2018-05-22 13:11:04 -04:00

165 lines
8.9 KiB
Python

from mock import patch
import pytest
from flask_principal import AnonymousIdentity
from endpoints.api import api
from endpoints.api.organization import OrganizationCollaboratorList
from endpoints.api.repositorynotification import RepositoryNotification
from endpoints.api.permission import RepositoryUserTransitivePermission
from endpoints.api.team import OrganizationTeamSyncing
from endpoints.api.test.shared import conduct_api_call
from endpoints.api.repository import RepositoryTrust
from endpoints.api.signing import RepositorySignatures
from endpoints.api.search import ConductRepositorySearch
from endpoints.api.superuser import SuperUserRepositoryBuildLogs, SuperUserRepositoryBuildResource
from endpoints.api.superuser import SuperUserRepositoryBuildStatus
from endpoints.api.appspecifictokens import AppTokens, AppToken
from endpoints.api.manifest import RepositoryManifest
from endpoints.api.trigger import BuildTrigger
from endpoints.test.shared import client_with_identity, toggle_feature
from test.fixtures import *
ORG_PARAMS = {'orgname': 'buynlarge'}
TEAM_PARAMS = {'orgname': 'buynlarge', 'teamname': 'owners'}
BUILD_PARAMS = {'build_uuid': 'test-1234'}
REPO_PARAMS = {'repository': 'devtable/someapp'}
SEARCH_PARAMS = {'query': ''}
NOTIFICATION_PARAMS = {'namespace': 'devtable', 'repository': 'devtable/simple', 'uuid': 'some uuid'}
TOKEN_PARAMS = {'token_uuid': 'someuuid'}
TRIGGER_PARAMS = {'repository': 'devtable/simple', 'trigger_uuid': 'someuuid'}
MANIFEST_PARAMS = {'repository': 'devtable/simple', 'manifestref': 'sha256:deadbeef'}
@pytest.mark.parametrize('resource,method,params,body,identity,expected', [
(AppTokens, 'GET', {}, {}, None, 401),
(AppTokens, 'GET', {}, {}, 'freshuser', 200),
(AppTokens, 'GET', {}, {}, 'reader', 200),
(AppTokens, 'GET', {}, {}, 'devtable', 200),
(AppTokens, 'POST', {}, {}, None, 403),
(AppTokens, 'POST', {}, {}, 'freshuser', 400),
(AppTokens, 'POST', {}, {}, 'reader', 400),
(AppTokens, 'POST', {}, {}, 'devtable', 400),
(AppToken, 'GET', TOKEN_PARAMS, {}, None, 401),
(AppToken, 'GET', TOKEN_PARAMS, {}, 'freshuser', 404),
(AppToken, 'GET', TOKEN_PARAMS, {}, 'reader', 404),
(AppToken, 'GET', TOKEN_PARAMS, {}, 'devtable', 404),
(AppToken, 'DELETE', TOKEN_PARAMS, {}, None, 403),
(AppToken, 'DELETE', TOKEN_PARAMS, {}, 'freshuser', 404),
(AppToken, 'DELETE', TOKEN_PARAMS, {}, 'reader', 404),
(AppToken, 'DELETE', TOKEN_PARAMS, {}, 'devtable', 404),
(RepositoryManifest, 'GET', MANIFEST_PARAMS, {}, None, 401),
(RepositoryManifest, 'GET', MANIFEST_PARAMS, {}, 'freshuser', 403),
(RepositoryManifest, 'GET', MANIFEST_PARAMS, {}, 'reader', 403),
(RepositoryManifest, 'GET', MANIFEST_PARAMS, {}, 'devtable', 404),
(OrganizationCollaboratorList, 'GET', ORG_PARAMS, None, None, 401),
(OrganizationCollaboratorList, 'GET', ORG_PARAMS, None, 'freshuser', 403),
(OrganizationCollaboratorList, 'GET', ORG_PARAMS, None, 'reader', 403),
(OrganizationCollaboratorList, 'GET', ORG_PARAMS, None, 'devtable', 200),
(OrganizationTeamSyncing, 'POST', TEAM_PARAMS, {}, None, 403),
(OrganizationTeamSyncing, 'POST', TEAM_PARAMS, {}, 'freshuser', 403),
(OrganizationTeamSyncing, 'POST', TEAM_PARAMS, {}, 'reader', 403),
(OrganizationTeamSyncing, 'POST', TEAM_PARAMS, {}, 'devtable', 400),
(OrganizationTeamSyncing, 'DELETE', TEAM_PARAMS, {}, None, 403),
(OrganizationTeamSyncing, 'DELETE', TEAM_PARAMS, {}, 'freshuser', 403),
(OrganizationTeamSyncing, 'DELETE', TEAM_PARAMS, {}, 'reader', 403),
(OrganizationTeamSyncing, 'DELETE', TEAM_PARAMS, {}, 'devtable', 200),
(ConductRepositorySearch, 'GET', SEARCH_PARAMS, None, None, 200),
(ConductRepositorySearch, 'GET', SEARCH_PARAMS, None, 'freshuser', 200),
(ConductRepositorySearch, 'GET', SEARCH_PARAMS, None, 'reader', 200),
(ConductRepositorySearch, 'GET', SEARCH_PARAMS, None, 'devtable', 200),
(SuperUserRepositoryBuildLogs, 'GET', BUILD_PARAMS, None, None, 401),
(SuperUserRepositoryBuildLogs, 'GET', BUILD_PARAMS, None, 'freshuser', 403),
(SuperUserRepositoryBuildLogs, 'GET', BUILD_PARAMS, None, 'reader', 403),
(SuperUserRepositoryBuildLogs, 'GET', BUILD_PARAMS, None, 'devtable', 400),
(SuperUserRepositoryBuildStatus, 'GET', BUILD_PARAMS, None, None, 401),
(SuperUserRepositoryBuildStatus, 'GET', BUILD_PARAMS, None, 'freshuser', 403),
(SuperUserRepositoryBuildStatus, 'GET', BUILD_PARAMS, None, 'reader', 403),
(SuperUserRepositoryBuildStatus, 'GET', BUILD_PARAMS, None, 'devtable', 400),
(SuperUserRepositoryBuildResource, 'GET', BUILD_PARAMS, None, None, 401),
(SuperUserRepositoryBuildResource, 'GET', BUILD_PARAMS, None, 'freshuser', 403),
(SuperUserRepositoryBuildResource, 'GET', BUILD_PARAMS, None, 'reader', 403),
(SuperUserRepositoryBuildResource, 'GET', BUILD_PARAMS, None, 'devtable', 404),
(RepositorySignatures, 'GET', REPO_PARAMS, {}, 'freshuser', 403),
(RepositorySignatures, 'GET', REPO_PARAMS, {}, 'reader', 403),
(RepositorySignatures, 'GET', REPO_PARAMS, {}, 'devtable', 404),
(RepositoryNotification, 'POST', NOTIFICATION_PARAMS, {}, None, 403),
(RepositoryNotification, 'POST', NOTIFICATION_PARAMS, {}, 'freshuser', 403),
(RepositoryNotification, 'POST', NOTIFICATION_PARAMS, {}, 'reader', 403),
(RepositoryNotification, 'POST', NOTIFICATION_PARAMS, {}, 'devtable', 400),
(RepositoryTrust, 'POST', REPO_PARAMS, {'trust_enabled': True}, None, 403),
(RepositoryTrust, 'POST', REPO_PARAMS, {'trust_enabled': True}, 'freshuser', 403),
(RepositoryTrust, 'POST', REPO_PARAMS, {'trust_enabled': True}, 'reader', 403),
(RepositoryTrust, 'POST', REPO_PARAMS, {'trust_enabled': True}, 'devtable', 404),
(BuildTrigger, 'GET', TRIGGER_PARAMS, {}, None, 401),
(BuildTrigger, 'GET', TRIGGER_PARAMS, {}, 'freshuser', 403),
(BuildTrigger, 'GET', TRIGGER_PARAMS, {}, 'reader', 403),
(BuildTrigger, 'GET', TRIGGER_PARAMS, {}, 'devtable', 404),
(BuildTrigger, 'DELETE', TRIGGER_PARAMS, {}, None, 403),
(BuildTrigger, 'DELETE', TRIGGER_PARAMS, {}, 'freshuser', 403),
(BuildTrigger, 'DELETE', TRIGGER_PARAMS, {}, 'reader', 403),
(BuildTrigger, 'DELETE', TRIGGER_PARAMS, {}, 'devtable', 404),
(BuildTrigger, 'PUT', TRIGGER_PARAMS, {}, None, 403),
(BuildTrigger, 'PUT', TRIGGER_PARAMS, {}, 'freshuser', 403),
(BuildTrigger, 'PUT', TRIGGER_PARAMS, {}, 'reader', 403),
(BuildTrigger, 'PUT', TRIGGER_PARAMS, {}, 'devtable', 400),
(RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'public/publicrepo'}, None, None, 401),
(RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'public/publicrepo'}, None, 'freshuser', 403),
(RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'public/publicrepo'}, None, 'reader', 403),
(RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'public/publicrepo'}, None, 'devtable', 403),
(RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'devtable/shared'}, None, None, 401),
(RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'devtable/shared'}, None, 'freshuser', 403),
(RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'devtable/shared'}, None, 'reader', 403),
(RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'devtable/shared'}, None, 'devtable', 404),
(RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'buynlarge/orgrepo'}, None, None, 401),
(RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'buynlarge/orgrepo'}, None, 'freshuser', 403),
(RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'buynlarge/orgrepo'}, None, 'reader', 403),
(RepositoryUserTransitivePermission, 'GET', {'username': 'A2O9','repository': 'buynlarge/orgrepo'}, None, 'devtable', 404),
(RepositoryUserTransitivePermission, 'GET', {'username': 'devtable','repository': 'devtable/shared'}, None, 'devtable', 200),
(RepositoryUserTransitivePermission, 'GET', {'username': 'devtable','repository': 'devtable/nope'}, None, 'devtable', 404),
])
def test_api_security(resource, method, params, body, identity, expected, client):
with client_with_identity(identity, client) as cl:
conduct_api_call(cl, resource, method, params, body, expected)
@pytest.mark.parametrize('is_superuser', [
(True),
(False),
])
@pytest.mark.parametrize('allow_nonsuperuser', [
(True),
(False),
])
@pytest.mark.parametrize('method, expected', [
('POST', 400),
('DELETE', 200),
])
def test_team_sync_security(is_superuser, allow_nonsuperuser, method, expected, client):
def is_superuser_method(_):
return is_superuser
with patch('auth.permissions.superusers.is_superuser', is_superuser_method):
with toggle_feature('NONSUPERUSER_TEAM_SYNCING_SETUP', allow_nonsuperuser):
with client_with_identity('devtable', client) as cl:
expect_success = is_superuser or allow_nonsuperuser
expected_status = expected if expect_success else 403
conduct_api_call(cl, OrganizationTeamSyncing, method, TEAM_PARAMS, {}, expected_status)