mirror of
https://pagure.io/fm-orchestrator.git
synced 2026-02-02 20:59:06 +08:00
Add authentication for product pages
This commit is contained in:
@@ -662,6 +662,21 @@ class Config(object):
|
|||||||
"stream has been released. If it has, the stream may be modified automatically "
|
"stream has been released. If it has, the stream may be modified automatically "
|
||||||
"to use a different support stream.",
|
"to use a different support stream.",
|
||||||
},
|
},
|
||||||
|
"product_pages_token_endpoint": {
|
||||||
|
"type": str,
|
||||||
|
"default": "",
|
||||||
|
"desc": "The endpoint to request a token to authenticate with Product Pages.",
|
||||||
|
},
|
||||||
|
"product_pages_oidc_client_id": {
|
||||||
|
"type": str,
|
||||||
|
"default": "",
|
||||||
|
"desc": "Client ID to authenticate with the token endpoint.",
|
||||||
|
},
|
||||||
|
"product_pages_client_secret": {
|
||||||
|
"type": str,
|
||||||
|
"default": "",
|
||||||
|
"desc": "Client secret to authenticate with the token endpoint.",
|
||||||
|
},
|
||||||
"product_pages_module_streams": {
|
"product_pages_module_streams": {
|
||||||
"type": dict,
|
"type": dict,
|
||||||
"default": {},
|
"default": {},
|
||||||
|
|||||||
@@ -387,6 +387,29 @@ def resolve_base_module_virtual_streams(db_session, name, streams):
|
|||||||
return new_streams
|
return new_streams
|
||||||
|
|
||||||
|
|
||||||
|
def _product_pages_oidc_auth():
|
||||||
|
"""
|
||||||
|
Obtain an OIDC access token to authenticate with Product Pages
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
token_response = requests.post(
|
||||||
|
conf.product_pages_token_endpoint,
|
||||||
|
{
|
||||||
|
'grant_type': 'client_credentials',
|
||||||
|
'client_id': conf.product_pages_oidc_client_id,
|
||||||
|
'client_secret': conf.product_pages_client_secret,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
token_response.raise_for_status()
|
||||||
|
except requests.exceptions.RequestException as e:
|
||||||
|
log.error(f"Product Pages authentication failed: {e}")
|
||||||
|
raise RuntimeError("Failed to authenticate with Product Pages.")
|
||||||
|
|
||||||
|
access_token = token_response.json()['access_token']
|
||||||
|
return {'Authorization': f'Bearer {access_token}'}
|
||||||
|
|
||||||
|
|
||||||
def _process_support_streams(db_session, mmd, params):
|
def _process_support_streams(db_session, mmd, params):
|
||||||
"""
|
"""
|
||||||
Check if any buildrequired base modules require a support stream suffix.
|
Check if any buildrequired base modules require a support stream suffix.
|
||||||
@@ -407,6 +430,17 @@ def _process_support_streams(db_session, mmd, params):
|
|||||||
elif not conf.product_pages_module_streams:
|
elif not conf.product_pages_module_streams:
|
||||||
log.debug(config_msg, "product_pages_module_streams")
|
log.debug(config_msg, "product_pages_module_streams")
|
||||||
return
|
return
|
||||||
|
elif not conf.product_pages_token_endpoint:
|
||||||
|
log.debug(config_msg, "product_pages_token_endpoint")
|
||||||
|
return
|
||||||
|
elif not conf.product_pages_oidc_client_id:
|
||||||
|
log.debug(config_msg, "product_pages_oidc_client_id")
|
||||||
|
return
|
||||||
|
elif not conf.product_pages_client_secret:
|
||||||
|
log.debug(config_msg, "product_pages_client_secret")
|
||||||
|
return
|
||||||
|
|
||||||
|
auth_header = _product_pages_oidc_auth()
|
||||||
|
|
||||||
buildrequire_overrides = params.get("buildrequire_overrides", {})
|
buildrequire_overrides = params.get("buildrequire_overrides", {})
|
||||||
|
|
||||||
@@ -427,7 +461,7 @@ def _process_support_streams(db_session, mmd, params):
|
|||||||
conf.product_pages_url.rstrip("/"), pp_release)
|
conf.product_pages_url.rstrip("/"), pp_release)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pp_rv = requests.get(schedule_url, timeout=15)
|
pp_rv = requests.get(schedule_url, timeout=15, headers=auth_header)
|
||||||
# raise exception if we receive 404
|
# raise exception if we receive 404
|
||||||
pp_rv.raise_for_status()
|
pp_rv.raise_for_status()
|
||||||
pp_json = pp_rv.json()
|
pp_json = pp_rv.json()
|
||||||
@@ -459,7 +493,7 @@ def _process_support_streams(db_session, mmd, params):
|
|||||||
Check if the stream has been released. Return True if it has.
|
Check if the stream has been released. Return True if it has.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
pp_rv = requests.get(url, timeout=15)
|
pp_rv = requests.get(url, timeout=15, headers=auth_header)
|
||||||
pp_json = pp_rv.json()
|
pp_json = pp_rv.json()
|
||||||
# Catch requests failures and JSON parsing errors
|
# Catch requests failures and JSON parsing errors
|
||||||
except (requests.exceptions.RequestException, ValueError):
|
except (requests.exceptions.RequestException, ValueError):
|
||||||
|
|||||||
@@ -2195,12 +2195,25 @@ class TestSubmitBuild:
|
|||||||
"module_build_service.common.config.Config.product_pages_schedule_task_name",
|
"module_build_service.common.config.Config.product_pages_schedule_task_name",
|
||||||
new_callable=PropertyMock,
|
new_callable=PropertyMock,
|
||||||
)
|
)
|
||||||
|
@patch(
|
||||||
|
"module_build_service.common.config.Config.product_pages_token_endpoint",
|
||||||
|
new_callable=PropertyMock,
|
||||||
|
)
|
||||||
|
@patch(
|
||||||
|
"module_build_service.common.config.Config.product_pages_oidc_client_id",
|
||||||
|
new_callable=PropertyMock,
|
||||||
|
)
|
||||||
|
@patch(
|
||||||
|
"module_build_service.common.config.Config.product_pages_client_secret",
|
||||||
|
new_callable=PropertyMock,
|
||||||
|
)
|
||||||
@patch("requests.get")
|
@patch("requests.get")
|
||||||
@patch("module_build_service.web.auth.get_user", return_value=user)
|
@patch("module_build_service.web.auth.get_user", return_value=user)
|
||||||
@patch("module_build_service.common.scm.SCM")
|
@patch("module_build_service.common.scm.SCM")
|
||||||
|
@patch("module_build_service.web.submit._product_pages_oidc_auth", return_value="authstring")
|
||||||
def test_submit_build_automatic_z_stream_detection(
|
def test_submit_build_automatic_z_stream_detection(
|
||||||
self, mocked_scm, mocked_get_user, mock_get, mock_pp_sched, mock_pp_streams,
|
self, mocked_oidc_auth, mocked_scm, mocked_get_user, mock_get, mock_pp_secret,
|
||||||
mock_pp_url,
|
mock_pp_id, mock_pp_endpoint, mock_pp_sched, mock_pp_streams, mock_pp_url,
|
||||||
mock_datetime, pp_url, pp_streams, pp_sched, get_rv, br_stream, br_override,
|
mock_datetime, pp_url, pp_streams, pp_sched, get_rv, br_stream, br_override,
|
||||||
expected_stream, utcnow,
|
expected_stream, utcnow,
|
||||||
):
|
):
|
||||||
@@ -2208,6 +2221,10 @@ class TestSubmitBuild:
|
|||||||
mock_pp_url.return_value = pp_url
|
mock_pp_url.return_value = pp_url
|
||||||
mock_pp_streams.return_value = pp_streams
|
mock_pp_streams.return_value = pp_streams
|
||||||
mock_pp_sched.return_value = pp_sched
|
mock_pp_sched.return_value = pp_sched
|
||||||
|
# Configure the OIDC auth
|
||||||
|
mock_pp_endpoint.return_value = "endpoint"
|
||||||
|
mock_pp_id.return_value = "client_id"
|
||||||
|
mock_pp_secret.return_value = "secret"
|
||||||
# Mock the Product Pages query
|
# Mock the Product Pages query
|
||||||
mock_get.return_value.json.return_value = get_rv
|
mock_get.return_value.json.return_value = get_rv
|
||||||
# Mock the date
|
# Mock the date
|
||||||
@@ -2255,7 +2272,8 @@ class TestSubmitBuild:
|
|||||||
expected_url = \
|
expected_url = \
|
||||||
"{}api/v7/releases/{}/schedule-tasks/?fields=name,date_finish".format(
|
"{}api/v7/releases/{}/schedule-tasks/?fields=name,date_finish".format(
|
||||||
pp_url, pp_release)
|
pp_url, pp_release)
|
||||||
mock_get.assert_called_once_with(expected_url, timeout=15)
|
mock_get.assert_called_once_with(expected_url, timeout=15, headers="authstring")
|
||||||
|
mocked_oidc_auth.assert_called()
|
||||||
else:
|
else:
|
||||||
mock_get.assert_not_called()
|
mock_get.assert_not_called()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user