Fully migrate API security tests into the pytest test suite

Also adds an additional test that ensures that at least one security test exists for every (api endpoint, http method) pair.
This commit is contained in:
Joseph Schorr 2018-07-08 18:33:21 +03:00
parent beebe6d5ed
commit 924dda296f
7 changed files with 1340 additions and 4493 deletions

View file

@ -38,16 +38,17 @@ def test_lookup_userfile(app, client):
storage_mock.stream_read_file = _stream_read_file storage_mock.stream_read_file = _stream_read_file
app.config['USERFILES_PATH'] = 'foo' app.config['USERFILES_PATH'] = 'foo'
Userfiles(app, distributed_storage=storage_mock) Userfiles(app, distributed_storage=storage_mock, path='mockuserfiles',
handler_name='mockuserfiles')
rv = client.open('/userfiles/' + uuid, method='GET') rv = client.open('/mockuserfiles/' + uuid, method='GET')
assert rv.status_code == 200 assert rv.status_code == 200
rv = client.open('/userfiles/' + upper_uuid, method='GET') rv = client.open('/mockuserfiles/' + upper_uuid, method='GET')
assert rv.status_code == 200 assert rv.status_code == 200
rv = client.open('/userfiles/' + bad_uuid, method='GET') rv = client.open('/mockuserfiles/' + bad_uuid, method='GET')
assert rv.status_code == 404 assert rv.status_code == 404
rv = client.open('/userfiles/foo/bar/baz', method='GET') rv = client.open('/mockuserfiles/foo/bar/baz', method='GET')
assert rv.status_code == 404 assert rv.status_code == 404

View file

@ -128,23 +128,23 @@ class DelegateUserfiles(object):
class Userfiles(object): class Userfiles(object):
def __init__(self, app=None, distributed_storage=None): def __init__(self, app=None, distributed_storage=None, path='userfiles',
handler_name='userfiles_handler'):
self.app = app self.app = app
if app is not None: if app is not None:
self.state = self.init_app(app, distributed_storage) self.state = self.init_app(app, distributed_storage, path=path, handler_name=handler_name)
else: else:
self.state = None self.state = None
def init_app(self, app, distributed_storage): def init_app(self, app, distributed_storage, path='userfiles', handler_name='userfiles_handler'):
location = app.config.get('USERFILES_LOCATION') location = app.config.get('USERFILES_LOCATION')
path = app.config.get('USERFILES_PATH', None) userfiles_path = app.config.get('USERFILES_PATH', None)
if path is not None: if userfiles_path is not None:
handler_name = 'userfiles_handlers' userfiles = DelegateUserfiles(app, distributed_storage, location, userfiles_path,
userfiles = DelegateUserfiles(app, distributed_storage, location, path,
handler_name=handler_name) handler_name=handler_name)
app.add_url_rule('/userfiles/<regex("[0-9a-zA-Z-]+"):file_id>', app.add_url_rule('/%s/<regex("[0-9a-zA-Z-]+"):file_id>' % path,
view_func=UserfilesHandlers.as_view(handler_name, view_func=UserfilesHandlers.as_view(handler_name,
distributed_storage=distributed_storage, distributed_storage=distributed_storage,
location=location, location=location,

File diff suppressed because it is too large Load diff

View file

@ -14,11 +14,11 @@ CSRF_TOKEN = '123csrfforme'
@contextmanager @contextmanager
def client_with_identity(auth_username, client): def client_with_identity(auth_username, client):
with client.session_transaction() as sess: with client.session_transaction() as sess:
sess[CSRF_TOKEN_KEY] = CSRF_TOKEN
if auth_username and auth_username is not None: if auth_username and auth_username is not None:
loaded = model.user.get_user(auth_username) loaded = model.user.get_user(auth_username)
sess['user_id'] = loaded.uuid sess['user_id'] = loaded.uuid
sess['login_time'] = datetime.datetime.now() sess['login_time'] = datetime.datetime.now()
sess[CSRF_TOKEN_KEY] = CSRF_TOKEN
else: else:
sess['user_id'] = 'anonymous' sess['user_id'] = 'anonymous'

View file

@ -7,6 +7,7 @@ import shutil
from flask import Flask, jsonify from flask import Flask, jsonify
from flask_login import LoginManager from flask_login import LoginManager
from flask_principal import identity_loaded, Permission, Identity, identity_changed, Principal from flask_principal import identity_loaded, Permission, Identity, identity_changed, Principal
from flask_mail import Mail
from peewee import SqliteDatabase, savepoint, InternalError from peewee import SqliteDatabase, savepoint, InternalError
from app import app as application from app import app as application
@ -14,6 +15,7 @@ from auth.permissions import on_identity_loaded
from data import model from data import model
from data.database import close_db_filter, db, configure from data.database import close_db_filter, db, configure
from data.model.user import LoginWrappedDBUser from data.model.user import LoginWrappedDBUser
from data.userfiles import Userfiles
from endpoints.api import api_bp from endpoints.api import api_bp
from endpoints.appr import appr_bp from endpoints.appr import appr_bp
from endpoints.web import web from endpoints.web import web
@ -124,6 +126,9 @@ def appconfig(database_uri):
"DATA_MODEL_CACHE_CONFIG": { "DATA_MODEL_CACHE_CONFIG": {
'engine': 'inmemory', 'engine': 'inmemory',
}, },
"USERFILES_PATH": "userfiles/",
"MAIL_SERVER": "",
"MAIL_DEFAULT_SENDER": 'support@quay.io',
} }
return conf return conf
@ -192,4 +197,8 @@ def app(appconfig, initialized_db):
app.register_blueprint(webhooks, url_prefix='/webhooks') app.register_blueprint(webhooks, url_prefix='/webhooks')
app.config.update(appconfig) app.config.update(appconfig)
Userfiles(app)
Mail(app)
return app return app

File diff suppressed because it is too large Load diff

View file

@ -42,6 +42,7 @@ class TestConfig(DefaultConfig):
BUILDLOGS_OPTIONS = ['devtable', 'building', 'deadbeef-dead-beef-dead-beefdeadbeef', False] BUILDLOGS_OPTIONS = ['devtable', 'building', 'deadbeef-dead-beef-dead-beefdeadbeef', False]
USERFILES_LOCATION = 'local_us' USERFILES_LOCATION = 'local_us'
USERFILES_PATH= "userfiles/"
FEATURE_SUPER_USERS = True FEATURE_SUPER_USERS = True
FEATURE_BILLING = True FEATURE_BILLING = True