From 362cc4d4416c79919e40d8d53120d1cbb4be5db1 Mon Sep 17 00:00:00 2001 From: Yuxiang Zhu Date: May 14 2019 06:17:42 +0000 Subject: [PATCH 1/7] CI/CD: Fix postmerge job commit flagging Pagure doesn't seem to allow to use the same `uid` for different commits. --- diff --git a/openshift/pipelines/templates/waiverdb-build.Jenkinsfile b/openshift/pipelines/templates/waiverdb-build.Jenkinsfile index 5444a5a..75efb96 100644 --- a/openshift/pipelines/templates/waiverdb-build.Jenkinsfile +++ b/openshift/pipelines/templates/waiverdb-build.Jenkinsfile @@ -533,7 +533,7 @@ def setBuildStatusOnPagurePR(percent, String comment) { } def flagCommit(status, percent, comment) { withPagureCreds { - it.flagCommit(username: 'c3i-jenkins', uid: 'ci-post-merge', status: status, + it.flagCommit(username: 'c3i-jenkins', uid: "ci-post-merge-${env.WAIVERDB_GIT_COMMIT.substring(0, 7)}", status: status, url: env.BUILD_URL, percent: percent, comment: comment, commit: env.WAIVERDB_GIT_COMMIT) } } From 994646673c0bd8b8419940eec33d590cd3b7b123 Mon Sep 17 00:00:00 2001 From: Lukas Holecek Date: May 15 2019 11:02:55 +0000 Subject: [PATCH 2/7] Use flask-cors library to support CORS headers Moves the CORS header support to the library. JIRA: FACTORY-4516 JIRA: FACTORY-4524 Signed-off-by: Lukas Holecek --- diff --git a/requirements.txt b/requirements.txt index f805c98..0e75e9f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,7 @@ fedora_messaging Flask Flask-RESTful!=0.3.6 Flask-SQLAlchemy +flask-cors SQLAlchemy gssapi flask-oidc diff --git a/tests/conftest.py b/tests/conftest.py index cf7eba5..3ba5f3b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -79,11 +79,6 @@ def enable_ssl(app, monkeypatch): @pytest.fixture() -def enable_cors(app, monkeypatch): - monkeypatch.setitem(app.config, 'CORS_URL', 'https://bodhi.fedoraproject.org') - - -@pytest.fixture() def enable_permission_mapping(app, monkeypatch): monkeypatch.setitem(app.config, 'PERMISSION_MAPPING', { diff --git a/tests/test_api_v10.py b/tests/test_api_v10.py index 38a3ece..8e02af6 100644 --- a/tests/test_api_v10.py +++ b/tests/test_api_v10.py @@ -638,68 +638,38 @@ def test_about_endpoint(client, trailing_slash): assert output['auth_method'] == client.application.config['AUTH_METHOD'] -@pytest.mark.usefixtures('enable_cors') -def test_cors_about(client, session): - r = client.get('/api/v1.0/about') - - assert 'Access-Control-Allow-Origin' in list(r.headers.keys()) - assert 'Access-Control-Allow-Headers' in list(r.headers.keys()) - assert 'Access-Control-Allow-Method' in list(r.headers.keys()) - assert r.headers['Access-Control-Allow-Origin'] == 'https://bodhi.fedoraproject.org' - assert r.headers['Access-Control-Allow-Headers'] == 'Content-Type' - assert r.headers['Access-Control-Allow-Method'] == 'POST, OPTIONS' - - output = json.loads(r.get_data(as_text=True)) - assert r.status_code == 200 - assert output['version'] == __version__ - - -def test_no_cors_about(client, session): - r = client.get('/api/v1.0/about') - - assert 'Access-Control-Allow-Origin' not in list(r.headers.keys()) - assert 'Access-Control-Allow-Headers' not in list(r.headers.keys()) - assert 'Access-Control-Allow-Method' not in list(r.headers.keys()) - - output = json.loads(r.get_data(as_text=True)) - assert r.status_code == 200 - assert output['version'] == __version__ - - -@pytest.mark.usefixtures('enable_cors') -def test_cors_waivers(client, session): - for i in range(0, 3): - create_waiver(session, subject_type='koji_build', subject_identifier="%d" % i, - testcase="case %d" % i, username='foo %d' % i, - product_version='foo-%d' % i, comment='bla bla bla') - r = client.get('/api/v1.0/waivers/') - - assert 'Access-Control-Allow-Origin' in list(r.headers.keys()) - assert 'Access-Control-Allow-Headers' in list(r.headers.keys()) - assert 'Access-Control-Allow-Method' in list(r.headers.keys()) - assert r.headers['Access-Control-Allow-Origin'] == 'https://bodhi.fedoraproject.org' - assert r.headers['Access-Control-Allow-Headers'] == 'Content-Type' - assert r.headers['Access-Control-Allow-Method'] == 'POST, OPTIONS' +def test_cors_good(client, session): + headers = { + 'Access-Control-Request-Method': 'POST', + 'Access-Control-Request-Headers': 'Content-Type', + 'Origin': 'https://bodhi.fedoraproject.org', + } + r = client.options( + '/api/v1.0/waivers/', + content_type='Content-Type', + headers=headers + ) - res_data = json.loads(r.get_data(as_text=True)) assert r.status_code == 200 - assert len(res_data['data']) == 3 + assert r.headers.get('Access-Control-Allow-Origin') == 'https://bodhi.fedoraproject.org' + assert 'POST' in r.headers.get('Access-Control-Allow-Methods', '').split(', ') -def test_no_cors_waivers(client, session): - for i in range(0, 3): - create_waiver(session, subject_type='koji_build', subject_identifier="%d" % i, - testcase="case %d" % i, username='foo %d' % i, - product_version='foo-%d' % i, comment='bla bla bla') - r = client.get('/api/v1.0/waivers/') - - assert 'Access-Control-Allow-Origin' not in list(r.headers.keys()) - assert 'Access-Control-Allow-Headers' not in list(r.headers.keys()) - assert 'Access-Control-Allow-Method' not in list(r.headers.keys()) +def test_cors_bad(client, session): + headers = { + 'Access-Control-Request-Method': 'POST', + 'Access-Control-Request-Headers': 'Content-Type', + 'Origin': 'localhost', + } + r = client.options( + '/api/v1.0/waivers/', + content_type='Content-Type', + headers=headers + ) - res_data = json.loads(r.get_data(as_text=True)) assert r.status_code == 200 - assert len(res_data['data']) == 3 + assert 'Access-Control-Allow-Origin' not in r.headers + assert 'Access-Control-Allow-Methods' not in r.headers @patch('waiverdb.auth.get_user', return_value=('foo', {})) diff --git a/waiverdb.spec b/waiverdb.spec index ef91d51..91a796f 100644 --- a/waiverdb.spec +++ b/waiverdb.spec @@ -31,6 +31,7 @@ BuildRequires: python3-sphinxcontrib-httpdomain BuildRequires: python3-sphinxcontrib-issuetracker BuildRequires: python3-flask BuildRequires: python3-sqlalchemy +BuildRequires: python3-flask-cors BuildRequires: python3-flask-restful BuildRequires: python3-flask-sqlalchemy BuildRequires: python3-psycopg2 @@ -47,6 +48,7 @@ BuildRequires: python3-prometheus_client BuildRequires: python3-six Requires: python3-flask Requires: python3-sqlalchemy +Requires: python3-flask-cors Requires: python3-flask-restful Requires: python3-flask-sqlalchemy Requires: python3-psycopg2 diff --git a/waiverdb/app.py b/waiverdb/app.py index b2181b1..96792ec 100644 --- a/waiverdb/app.py +++ b/waiverdb/app.py @@ -8,6 +8,7 @@ except ImportError: from urlparse import urlparse, urlunsplit from flask import Flask, current_app +from flask_cors import CORS from flask_migrate import Migrate from sqlalchemy import event from sqlalchemy.exc import ProgrammingError @@ -23,6 +24,18 @@ from werkzeug.exceptions import default_exceptions from waiverdb.monitor import db_hook_event_listeners +def enable_cors(app): + """ + Enables CORS headers. + """ + # backward compatibility with old CORS_URL option + cors_url = app.config.get('CORS_URL') + if cors_url: + app.config['CORS_ORIGINS'] = cors_url + + CORS(app) + + def load_config(app): # Load default config, then override that with a config file if os.getenv('DEV') == 'true': @@ -63,18 +76,6 @@ def populate_db_config(app): app.config['SQLALCHEMY_DATABASE_URI'] = dburi -def insert_headers(response): - """ Insert the CORS headers for the give response if there are any - configured for the application. - """ - cors_url = current_app.config.get('CORS_URL') - if cors_url: - response.headers['Access-Control-Allow-Origin'] = cors_url - response.headers['Access-Control-Allow-Headers'] = 'Content-Type' - response.headers['Access-Control-Allow-Method'] = 'POST, OPTIONS' - return response - - # applicaiton factory http://flask.pocoo.org/docs/0.12/patterns/appfactories/ def create_app(config_obj=None): app = Flask(__name__) @@ -107,11 +108,11 @@ def create_app(config_obj=None): app.add_url_rule('/healthcheck', view_func=healthcheck) register_event_handlers(app) - app.after_request(insert_headers) - # initialize DB event listeners from the monitor module app.before_first_request(db_hook_event_listeners) + enable_cors(app) + return app diff --git a/waiverdb/config.py b/waiverdb/config.py index 3a1fe61..0fa2338 100644 --- a/waiverdb/config.py +++ b/waiverdb/config.py @@ -62,3 +62,5 @@ class TestingConfig(Config): OIDC_REQUIRED_SCOPE = 'waiverdb_scope' OIDC_RESOURCE_SERVER_ONLY = True SUPERUSERS = ['bodhi'] + + CORS_ORIGINS = 'https://bodhi.fedoraproject.org' From ce74a95fb1b968cca8a9931e9b7dfdde0acbed9a Mon Sep 17 00:00:00 2001 From: Giulia Naponiello Date: May 15 2019 11:56:09 +0000 Subject: [PATCH 3/7] Release notes 1.1.0 Signed-off-by: Giulia Naponiello --- diff --git a/docs/release-notes.rst b/docs/release-notes.rst index 0ebadd9..fca6007 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -2,6 +2,31 @@ Release Notes ============= +WaiverDB 1.1.0 +============== + +Released 15 May 2019 + +* Restrict waiver creation based on users/groups and testcase: introduce access + control based on the users/groups and the testcase. + Groups need to be defined in LDAP. + New configuration is required to enable this feature: + + * ``PERMISSION_MAPPING``: dictionary with keys as regex applied to test cases + and values as dictionaries with "users" and "groups" allowed to submit waivers + for that matching test case. + If not specified, the feature is not enabled. + * ``LDAP_HOST`` and ``LDAP_BASE``: required to query the LDAP system. + Required if ``PERMISSION_MAPPING`` is defined. + +* Add ``proxied_by`` in the CLI: in the API is possible to define a username on + whose behalf the caller is proxying the submittion of a waiver. + This change provides this possibility also in the CLI. This is updated also to + reflect the recent changes regarding the access control. + +* Allow optional trailing slash for about endpoint: accessing "api/v1.0/about/" + won't give 404 anymore. + WaiverDB 1.0.0 ============== From 5214738a090f490aa602b117e3c80ff0ca0446d9 Mon Sep 17 00:00:00 2001 From: Lukas Holecek Date: May 15 2019 13:13:00 +0000 Subject: [PATCH 4/7] Automatic commit of release 1.1.0 --- diff --git a/waiverdb.spec b/waiverdb.spec index ef91d51..d3245ad 100644 --- a/waiverdb.spec +++ b/waiverdb.spec @@ -1,4 +1,4 @@ -%global upstream_version 1.0.0 +%global upstream_version 1.1.0 %if 0%{?fedora} || 0%{?rhel} > 7 %bcond_without server @@ -9,7 +9,7 @@ %endif Name: waiverdb -Version: 1.0.0 +Version: 1.1.0 Release: 1%{?dist} Summary: Service for waiving results in ResultsDB License: GPLv2+ diff --git a/waiverdb/__init__.py b/waiverdb/__init__.py index 0d26dfc..ac0710f 100644 --- a/waiverdb/__init__.py +++ b/waiverdb/__init__.py @@ -1,2 +1,2 @@ # SPDX-License-Identifier: GPL-2.0+ -__version__ = '1.0.0' +__version__ = '1.1.0' From 85f52ec0643618bbeb636c7d742eba86a8a76a3e Mon Sep 17 00:00:00 2001 From: Lukas Holecek Date: May 16 2019 04:56:26 +0000 Subject: [PATCH 5/7] Fix description content type for Python package By default the content type for description in set in "setup.py" is reStructuredText. Fixes uploading the package with to PyPI twine. See also: https://pypi.org/help/#description-content-type Signed-off-by: Lukas Holecek --- diff --git a/setup.py b/setup.py index c2950fc..8cfa69c 100644 --- a/setup.py +++ b/setup.py @@ -31,6 +31,7 @@ setup(name='waiverdb', version=get_project_version(), description='An engine for storing waivers against test results.', long_description=README, + long_description_content_type="text/markdown", author='Red Hat, Inc.', author_email='qa-devel@lists.fedoraproject.org', license='GPLv2+', From 093d9466f026ce62b9eb1a30b045f2eba5eda654 Mon Sep 17 00:00:00 2001 From: Giulia Naponiello Date: May 17 2019 07:00:37 +0000 Subject: [PATCH 6/7] Merge #328 `Use flask-cors library to support CORS headers` --- diff --git a/requirements.txt b/requirements.txt index f805c98..0e75e9f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,6 +5,7 @@ fedora_messaging Flask Flask-RESTful!=0.3.6 Flask-SQLAlchemy +flask-cors SQLAlchemy gssapi flask-oidc diff --git a/tests/conftest.py b/tests/conftest.py index cf7eba5..3ba5f3b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -79,11 +79,6 @@ def enable_ssl(app, monkeypatch): @pytest.fixture() -def enable_cors(app, monkeypatch): - monkeypatch.setitem(app.config, 'CORS_URL', 'https://bodhi.fedoraproject.org') - - -@pytest.fixture() def enable_permission_mapping(app, monkeypatch): monkeypatch.setitem(app.config, 'PERMISSION_MAPPING', { diff --git a/tests/test_api_v10.py b/tests/test_api_v10.py index 38a3ece..8e02af6 100644 --- a/tests/test_api_v10.py +++ b/tests/test_api_v10.py @@ -638,68 +638,38 @@ def test_about_endpoint(client, trailing_slash): assert output['auth_method'] == client.application.config['AUTH_METHOD'] -@pytest.mark.usefixtures('enable_cors') -def test_cors_about(client, session): - r = client.get('/api/v1.0/about') - - assert 'Access-Control-Allow-Origin' in list(r.headers.keys()) - assert 'Access-Control-Allow-Headers' in list(r.headers.keys()) - assert 'Access-Control-Allow-Method' in list(r.headers.keys()) - assert r.headers['Access-Control-Allow-Origin'] == 'https://bodhi.fedoraproject.org' - assert r.headers['Access-Control-Allow-Headers'] == 'Content-Type' - assert r.headers['Access-Control-Allow-Method'] == 'POST, OPTIONS' - - output = json.loads(r.get_data(as_text=True)) - assert r.status_code == 200 - assert output['version'] == __version__ - - -def test_no_cors_about(client, session): - r = client.get('/api/v1.0/about') - - assert 'Access-Control-Allow-Origin' not in list(r.headers.keys()) - assert 'Access-Control-Allow-Headers' not in list(r.headers.keys()) - assert 'Access-Control-Allow-Method' not in list(r.headers.keys()) - - output = json.loads(r.get_data(as_text=True)) - assert r.status_code == 200 - assert output['version'] == __version__ - - -@pytest.mark.usefixtures('enable_cors') -def test_cors_waivers(client, session): - for i in range(0, 3): - create_waiver(session, subject_type='koji_build', subject_identifier="%d" % i, - testcase="case %d" % i, username='foo %d' % i, - product_version='foo-%d' % i, comment='bla bla bla') - r = client.get('/api/v1.0/waivers/') - - assert 'Access-Control-Allow-Origin' in list(r.headers.keys()) - assert 'Access-Control-Allow-Headers' in list(r.headers.keys()) - assert 'Access-Control-Allow-Method' in list(r.headers.keys()) - assert r.headers['Access-Control-Allow-Origin'] == 'https://bodhi.fedoraproject.org' - assert r.headers['Access-Control-Allow-Headers'] == 'Content-Type' - assert r.headers['Access-Control-Allow-Method'] == 'POST, OPTIONS' +def test_cors_good(client, session): + headers = { + 'Access-Control-Request-Method': 'POST', + 'Access-Control-Request-Headers': 'Content-Type', + 'Origin': 'https://bodhi.fedoraproject.org', + } + r = client.options( + '/api/v1.0/waivers/', + content_type='Content-Type', + headers=headers + ) - res_data = json.loads(r.get_data(as_text=True)) assert r.status_code == 200 - assert len(res_data['data']) == 3 + assert r.headers.get('Access-Control-Allow-Origin') == 'https://bodhi.fedoraproject.org' + assert 'POST' in r.headers.get('Access-Control-Allow-Methods', '').split(', ') -def test_no_cors_waivers(client, session): - for i in range(0, 3): - create_waiver(session, subject_type='koji_build', subject_identifier="%d" % i, - testcase="case %d" % i, username='foo %d' % i, - product_version='foo-%d' % i, comment='bla bla bla') - r = client.get('/api/v1.0/waivers/') - - assert 'Access-Control-Allow-Origin' not in list(r.headers.keys()) - assert 'Access-Control-Allow-Headers' not in list(r.headers.keys()) - assert 'Access-Control-Allow-Method' not in list(r.headers.keys()) +def test_cors_bad(client, session): + headers = { + 'Access-Control-Request-Method': 'POST', + 'Access-Control-Request-Headers': 'Content-Type', + 'Origin': 'localhost', + } + r = client.options( + '/api/v1.0/waivers/', + content_type='Content-Type', + headers=headers + ) - res_data = json.loads(r.get_data(as_text=True)) assert r.status_code == 200 - assert len(res_data['data']) == 3 + assert 'Access-Control-Allow-Origin' not in r.headers + assert 'Access-Control-Allow-Methods' not in r.headers @patch('waiverdb.auth.get_user', return_value=('foo', {})) diff --git a/waiverdb.spec b/waiverdb.spec index d3245ad..0dd4436 100644 --- a/waiverdb.spec +++ b/waiverdb.spec @@ -31,6 +31,7 @@ BuildRequires: python3-sphinxcontrib-httpdomain BuildRequires: python3-sphinxcontrib-issuetracker BuildRequires: python3-flask BuildRequires: python3-sqlalchemy +BuildRequires: python3-flask-cors BuildRequires: python3-flask-restful BuildRequires: python3-flask-sqlalchemy BuildRequires: python3-psycopg2 @@ -47,6 +48,7 @@ BuildRequires: python3-prometheus_client BuildRequires: python3-six Requires: python3-flask Requires: python3-sqlalchemy +Requires: python3-flask-cors Requires: python3-flask-restful Requires: python3-flask-sqlalchemy Requires: python3-psycopg2 diff --git a/waiverdb/app.py b/waiverdb/app.py index b2181b1..96792ec 100644 --- a/waiverdb/app.py +++ b/waiverdb/app.py @@ -8,6 +8,7 @@ except ImportError: from urlparse import urlparse, urlunsplit from flask import Flask, current_app +from flask_cors import CORS from flask_migrate import Migrate from sqlalchemy import event from sqlalchemy.exc import ProgrammingError @@ -23,6 +24,18 @@ from werkzeug.exceptions import default_exceptions from waiverdb.monitor import db_hook_event_listeners +def enable_cors(app): + """ + Enables CORS headers. + """ + # backward compatibility with old CORS_URL option + cors_url = app.config.get('CORS_URL') + if cors_url: + app.config['CORS_ORIGINS'] = cors_url + + CORS(app) + + def load_config(app): # Load default config, then override that with a config file if os.getenv('DEV') == 'true': @@ -63,18 +76,6 @@ def populate_db_config(app): app.config['SQLALCHEMY_DATABASE_URI'] = dburi -def insert_headers(response): - """ Insert the CORS headers for the give response if there are any - configured for the application. - """ - cors_url = current_app.config.get('CORS_URL') - if cors_url: - response.headers['Access-Control-Allow-Origin'] = cors_url - response.headers['Access-Control-Allow-Headers'] = 'Content-Type' - response.headers['Access-Control-Allow-Method'] = 'POST, OPTIONS' - return response - - # applicaiton factory http://flask.pocoo.org/docs/0.12/patterns/appfactories/ def create_app(config_obj=None): app = Flask(__name__) @@ -107,11 +108,11 @@ def create_app(config_obj=None): app.add_url_rule('/healthcheck', view_func=healthcheck) register_event_handlers(app) - app.after_request(insert_headers) - # initialize DB event listeners from the monitor module app.before_first_request(db_hook_event_listeners) + enable_cors(app) + return app diff --git a/waiverdb/config.py b/waiverdb/config.py index 3a1fe61..0fa2338 100644 --- a/waiverdb/config.py +++ b/waiverdb/config.py @@ -62,3 +62,5 @@ class TestingConfig(Config): OIDC_REQUIRED_SCOPE = 'waiverdb_scope' OIDC_RESOURCE_SERVER_ONLY = True SUPERUSERS = ['bodhi'] + + CORS_ORIGINS = 'https://bodhi.fedoraproject.org' From b25d7845b86a4004da99ed70b053115ac6f0fb55 Mon Sep 17 00:00:00 2001 From: Lukas Holecek Date: May 17 2019 14:05:34 +0000 Subject: [PATCH 7/7] SUPERUSERS follow PERMISSION_MAPPING Signed-off-by: Lukas Holecek --- diff --git a/tests/conftest.py b/tests/conftest.py index 3ba5f3b..dc5bd2f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -80,12 +80,14 @@ def enable_ssl(app, monkeypatch): @pytest.fixture() def enable_permission_mapping(app, monkeypatch): - monkeypatch.setitem(app.config, 'PERMISSION_MAPPING', - { - "^testcase1.*": {"groups": ["factory-2-0"], "users": []}, # noqa - "^testcase2.*": {"groups": [], "users": ["foo"]}, # noqa - "^testcase4.*": {"groups": [], "users": []} # noqa - }) + permission_mapping = { + "^testcase1.*": {"groups": ["factory-2-0"], "users": ["bodhi"]}, + "^testcase2.*": {"groups": [], "users": ["bodhi", "foo"]}, + "^testcase3.*": {"groups": [], "users": ["bodhi"]}, + "^testcase4.*": {"groups": [], "users": []}, + "^testcase5.*": {"groups": [], "users": ["foo"]}, + } + monkeypatch.setitem(app.config, 'PERMISSION_MAPPING', permission_mapping) @pytest.fixture() diff --git a/tests/test_access_control.py b/tests/test_access_control.py index 5778e17..ad5a534 100644 --- a/tests/test_access_control.py +++ b/tests/test_access_control.py @@ -119,8 +119,8 @@ class TestAccessControl(object): content_type='application/json', headers=self.headers) res_data = json.loads(r.get_data(as_text=True)) assert r.status_code == 401 - assert res_data['message'] == ("You are not authorized to submit a waiver " - "for the test case testcase3") + assert res_data['message'] == \ + "User foo is not authorized to waive test cases testcase3" @pytest.mark.usefixtures('enable_ldap_host') @pytest.mark.usefixtures('enable_ldap_base') @@ -134,8 +134,8 @@ class TestAccessControl(object): content_type='application/json', headers=self.headers) res_data = json.loads(r.get_data(as_text=True)) assert r.status_code == 401 - assert res_data['message'] == ("You are not authorized to submit a waiver " - "for the test case testcase3") + assert res_data['message'] == \ + "User foo is not authorized to waive test cases testcase3" @pytest.mark.usefixtures('enable_ldap_host') @pytest.mark.usefixtures('enable_ldap_base') @@ -162,6 +162,21 @@ class TestAccessControl(object): @pytest.mark.usefixtures('enable_ldap_host') @pytest.mark.usefixtures('enable_ldap_base') @mock.patch('waiverdb.auth.get_user', return_value=('bodhi', {})) + @mock.patch('waiverdb.api_v1.WaiversResource.get_group_membership', + return_value=(['factory-2-0', 'something-else'])) + def test_superuser_has_no_permission(self, mocked_conn, mock_get_user, client, session): + self.data['testcase'] = 'testcase5' + self.data['username'] = 'foo' + r = client.post('/api/v1.0/waivers/', data=json.dumps(self.data), + content_type='application/json', headers=self.headers) + res_data = json.loads(r.get_data(as_text=True)) + assert r.status_code == 401 + assert res_data['message'] == \ + "User bodhi is not authorized to waive test cases testcase5" + + @pytest.mark.usefixtures('enable_ldap_host') + @pytest.mark.usefixtures('enable_ldap_base') + @mock.patch('waiverdb.auth.get_user', return_value=('bodhi', {})) @mock.patch('requests.request', side_effect=Unauthorized('You are not authorized to submit a waiver for the test ' 'case testcase3')) diff --git a/waiverdb/api_v1.py b/waiverdb/api_v1.py index 929933b..5f1086a 100644 --- a/waiverdb/api_v1.py +++ b/waiverdb/api_v1.py @@ -362,8 +362,8 @@ class WaiversResource(Resource): raise Unauthorized(f'Couldn\'t find user {user} in LDAP') if set(group_membership) & set(allowed_groups): return True - raise Unauthorized(('You are not authorized to submit a waiver ' - f'for the test case {testcase}')) + raise Unauthorized( + f'User {user} is not authorized to waive test cases {testcase}') def _create_waiver(self, args, user): proxied_by = None @@ -419,6 +419,8 @@ class WaiversResource(Resource): if not args['testcase']: raise BadRequest({'testcase': 'Missing required parameter in the JSON body'}) + if proxied_by: + self.verify_authorization(proxied_by, args['testcase']) self.verify_authorization(user, args['testcase']) # brew-build is an alias for koji_build