From 66bdd0ff9b583ca4b8efc0331f8a9e8aca5c472f Mon Sep 17 00:00:00 2001 From: nacho Date: Wed, 8 Feb 2023 11:36:48 +0100 Subject: [PATCH 1/7] add superadmin check in nginx --- services/nginx/nginx.conf | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/services/nginx/nginx.conf b/services/nginx/nginx.conf index 2599f779..3facf51d 100644 --- a/services/nginx/nginx.conf +++ b/services/nginx/nginx.conf @@ -14,28 +14,28 @@ http { } map "$request_method:$uri:$ssl_client_s_dn_cn" $invoker_error_message { default 'SUCCESS'; - "~*(PUT|DELETE):.*:(?!invoker)(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; + "~*(PUT|DELETE):.*:(?!(invoker|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $provider_error_message { default 'SUCCESS'; - "~*(PUT|DELETE|PATCH):.*:(?!amf)(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be amf"}'; + "~*(PUT|DELETE|PATCH):.*:(?!(amf|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be amf"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $publish_error_message { default 'SUCCESS'; - "~*.*:.*:(?!(apf|ccf))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; + "~*.*:.*:(?!(apf|ccf|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $discover_error_message { default 'SUCCESS'; - "~*.*:.*:(?!(invoker|ccf))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; + "~*.*:.*:(?!(invoker|ccf|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $security_error_message { default 'SUCCESS'; - "~*DELETE:.*:(?!aef)(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; - "~*PUT:.*:(?!invoker)(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; - "~*GET:.*:(?!aef)(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; - "~*POST:.*/update:(?!invoker)(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; - "~*POST:.*/delete:(?!aef)(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; - "~*POST:.*/token:(?!invoker)(.*)" '{"error":"unauthorized_client", "error_description":"Role not authorized for this API route"}'; + "~*DELETE:.*:(?!(aef|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; + "~*PUT:.*:(?!(invoker|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; + "~*GET:.*:(?!(aef|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; + "~*POST:.*/update:(?!(invoker|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; + "~*POST:.*/delete:(?!(aef|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; + "~*POST:.*/token:(?!(invoker|superadmin))(.*)" '{"error":"unauthorized_client", "error_description":"Role not authorized for this API route"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $events_error_message { default 'SUCCESS'; From 880ac1d4799d884677f9a2d41064286bf7c29774 Mon Sep 17 00:00:00 2001 From: nacho Date: Wed, 1 Mar 2023 23:18:05 +0100 Subject: [PATCH 2/7] add internal messages to remove security contexts and services) --- .../controllers/default_controller.py | 2 +- .../api_invoker_management/core/publisher.py | 1 + .../core/provider_enrolment_details_api.py | 3 ++ .../api_provider_management/core/publisher.py | 10 +++++++ .../api_provider_management/core/resources.py | 4 ++- .../requirements.txt | 2 ++ .../capif_events/core/consumer_messager.py | 4 +-- .../published_apis/__main__.py | 8 +++++ .../published_apis/core/consumer_messager.py | 29 +++++++++++++++++++ .../core/internal_service_ops.py | 13 +++++++++ .../requirements.txt | 1 + .../capif_security/core/consumer_messager.py | 7 +++-- .../core/internal_security_ops.py | 17 ++++++++++- 13 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/publisher.py create mode 100644 services/TS29222_CAPIF_Publish_Service_API/published_apis/core/consumer_messager.py create mode 100644 services/TS29222_CAPIF_Publish_Service_API/published_apis/core/internal_service_ops.py diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/controllers/default_controller.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/controllers/default_controller.py index d51968e6..92a71e56 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/controllers/default_controller.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/controllers/default_controller.py @@ -34,7 +34,7 @@ def onboarded_invokers_onboarding_id_delete(onboarding_id): # noqa: E501 if res.status_code == 204: current_app.logger.info("Invoker Removed") publisher_ops.publish_message("events", "API_INVOKER_UPDATED") - publisher_ops.publish_message("internal-messages", "invoker-removed:"+onboarding_id) + publisher_ops.publish_message("internal-messages", f"invoker-removed:{onboarding_id}") return res diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/publisher.py b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/publisher.py index f7b0c3c4..3898c4b8 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/publisher.py +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/api_invoker_management/core/publisher.py @@ -1,5 +1,6 @@ import redis import sys +from flask import current_app class Publisher(): diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py index b8a1fb9e..efcb447a 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py @@ -74,9 +74,12 @@ def delete_api_provider_enrolment_details(self, api_prov_dom_id): if isinstance(result, Response): return result + apf_id = [ provider_func['api_prov_func_id'] for provider_func in result["api_prov_funcs"] if provider_func['api_prov_func_role'] == 'APF' ] + aef_id = [ provider_func['api_prov_func_id'] for provider_func in result["api_prov_funcs"] if provider_func['api_prov_func_role'] == 'AEF' ] mycol.delete_one({'api_prov_dom_id': api_prov_dom_id}) out = "The provider matching apiProvDomainId " + api_prov_dom_id + " was offboarded." current_app.logger.debug("Removed provider domain from database") + self.publish_ops.publish_message("internal-messages", f"provider-removed:{apf_id[0]}:{aef_id[0]}") return make_response(object=out, status=204) except Exception as e: diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/publisher.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/publisher.py new file mode 100644 index 00000000..38d7259f --- /dev/null +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/publisher.py @@ -0,0 +1,10 @@ +import redis +import sys + +class Publisher(): + + def __init__(self): + self. r = redis.Redis(host='redis', port=6379, db=0) + + def publish_message(self, channel, message): + self.r.publish(channel, message) \ No newline at end of file diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/resources.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/resources.py index 94e29ec0..86e99d4b 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/resources.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/resources.py @@ -1,7 +1,9 @@ from abc import ABC, abstractmethod from ..db.db import MongoDatabse +from .publisher import Publisher class Resource(ABC): def __init__(self): - self.db = MongoDatabse() \ No newline at end of file + self.db = MongoDatabse() + self.publish_ops = Publisher() \ No newline at end of file diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt b/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt index 0660f523..edd13c6f 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt +++ b/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt @@ -4,6 +4,8 @@ python_dateutil >= 2.6.0 setuptools >= 21.0.0 Flask == 2.0.3 pymongo == 4.0.1 +redis flask_jwt_extended +flask_executor pyopenssl diff --git a/services/TS29222_CAPIF_Events_API/capif_events/core/consumer_messager.py b/services/TS29222_CAPIF_Events_API/capif_events/core/consumer_messager.py index dc61cd1e..4424fba9 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/core/consumer_messager.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/core/consumer_messager.py @@ -25,10 +25,10 @@ def listen(self): self.notification.send_notifications(raw_message["data"].decode('utf-8')) elif raw_message["type"] == "message" and raw_message["channel"].decode('utf-8') == "internal-messages": - message, invoker_id = raw_message["data"].decode('utf-8').split(":") + message, *invoker_id = raw_message["data"].decode('utf-8').split(":") if message == "invoker-removed": current_app.logger.debug("Recevived message, invoker remove, removing event subscriptions") - self.event_ops.delete_all_events(invoker_id) + self.event_ops.delete_all_events(invoker_id[0]) diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/__main__.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/__main__.py index b816113f..d6936035 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/__main__.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/__main__.py @@ -10,6 +10,8 @@ from pymongo import MongoClient from .config import Config from logging.handlers import RotatingFileHandler +from .core.consumer_messager import Subscriber +from flask_executor import Executor def configure_logging(app): @@ -50,6 +52,12 @@ def verbose_formatter(): jwt = JWTManager(app.app) configure_logging(app.app) +executor = Executor(app.app) +subscriber = Subscriber() + +@app.app.before_first_request +def up_listener(): + executor.submit(subscriber.listen) if __name__ == '__main__': diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/consumer_messager.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/consumer_messager.py new file mode 100644 index 00000000..49666f01 --- /dev/null +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/consumer_messager.py @@ -0,0 +1,29 @@ +# subscriber.py +import redis +import time +import sys +import json +import asyncio +from threading import Thread +from .internal_service_ops import InternalServiceOps +from flask import current_app + +class Subscriber(): + + def __init__(self): + self.r = redis.Redis(host='redis', port=6379, db=0) + self.security_ops = InternalServiceOps() + self.p = self.r.pubsub() + self.p.subscribe("internal-messages") + + def listen(self): + current_app.logger.info("Listening publish messages") + for raw_message in self.p.listen(): + if raw_message["type"] == "message" and raw_message["channel"].decode('utf-8') == "internal-messages": + message, *apf_id = raw_message["data"].decode('utf-8').split(":") + if message == "provider-removed": + self.security_ops.delete_intern_service(apf_id[0]) + + + + diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/internal_service_ops.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/internal_service_ops.py new file mode 100644 index 00000000..70855c57 --- /dev/null +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/internal_service_ops.py @@ -0,0 +1,13 @@ + +from flask import current_app +from .resources import Resource + +class InternalServiceOps(Resource): + + def delete_intern_service(self, apf_id): + + current_app.logger.info("Provider removed, removing services published by APF") + mycol = self.db.get_col_by_name(self.db.service_api_descriptions) + my_query = {'apf_id': apf_id} + mycol.delete_many(my_query) + current_app.logger.info("Removed service") \ No newline at end of file diff --git a/services/TS29222_CAPIF_Publish_Service_API/requirements.txt b/services/TS29222_CAPIF_Publish_Service_API/requirements.txt index 0e173577..e7e09b43 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/requirements.txt +++ b/services/TS29222_CAPIF_Publish_Service_API/requirements.txt @@ -5,6 +5,7 @@ setuptools >= 21.0.0 Flask == 2.0.3 pymongo == 4.0.1 flask_jwt_extended +flask_executor pyopenssl redis diff --git a/services/TS29222_CAPIF_Security_API/capif_security/core/consumer_messager.py b/services/TS29222_CAPIF_Security_API/capif_security/core/consumer_messager.py index 71309d8f..a9f8293e 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/core/consumer_messager.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/core/consumer_messager.py @@ -17,11 +17,14 @@ def __init__(self): self.p.subscribe("internal-messages") def listen(self): + current_app.logger.info("Listening security context messages") for raw_message in self.p.listen(): if raw_message["type"] == "message" and raw_message["channel"].decode('utf-8') == "internal-messages": - message, invoker_id = raw_message["data"].decode('utf-8').split(":") + message, *ids = raw_message["data"].decode('utf-8').split(":") if message == "invoker-removed": - self.security_ops.delete_intern_servicesecurity(invoker_id) + self.security_ops.delete_intern_servicesecurity(ids[0]) + if message == "provider-removed": + self.security_ops.update_intern_servicesecurity(ids[1]) diff --git a/services/TS29222_CAPIF_Security_API/capif_security/core/internal_security_ops.py b/services/TS29222_CAPIF_Security_API/capif_security/core/internal_security_ops.py index 5b30874f..8195ecd8 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/core/internal_security_ops.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/core/internal_security_ops.py @@ -10,4 +10,19 @@ def delete_intern_servicesecurity(self, api_invoker_id): mycol = self.db.get_col_by_name(self.db.security_info) my_query = {'api_invoker_id': api_invoker_id} mycol.delete_many(my_query) - current_app.logger.info("Removed security context") \ No newline at end of file + current_app.logger.info("Removed security context") + + def update_intern_servicesecurity(self, aef_id): + + current_app.logger.info("Provider Removed, updating security context") + security_col = self.db.get_col_by_name(self.db.security_info) + + security_contexts = security_col.find({"security_info.aef_id":aef_id}) + + for security_context in security_contexts: + new_security_info = [info for info in security_context["security_info"] if info["aef_id"]!=aef_id] + security_context["security_info"] = new_security_info + + security_col.update_one({'api_invoker_id':security_context["api_invoker_id"]}, {"$set":security_context}) + + current_app.logger.info("Updated security context") \ No newline at end of file From 8bd23ad89d6b681d37c00973f6a19a11546f5865 Mon Sep 17 00:00:00 2001 From: nacho Date: Fri, 3 Mar 2023 11:50:38 +0100 Subject: [PATCH 3/7] update security context if remove service --- .../core/provider_enrolment_details_api.py | 2 +- .../published_apis/controllers/default_controller.py | 1 + .../published_apis/core/consumer_messager.py | 4 ++-- .../capif_security/core/consumer_messager.py | 7 ++++--- .../capif_security/core/internal_security_ops.py | 8 ++++---- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py index efcb447a..3ddab693 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py +++ b/services/TS29222_CAPIF_API_Provider_Management_API/api_provider_management/core/provider_enrolment_details_api.py @@ -79,7 +79,7 @@ def delete_api_provider_enrolment_details(self, api_prov_dom_id): mycol.delete_one({'api_prov_dom_id': api_prov_dom_id}) out = "The provider matching apiProvDomainId " + api_prov_dom_id + " was offboarded." current_app.logger.debug("Removed provider domain from database") - self.publish_ops.publish_message("internal-messages", f"provider-removed:{apf_id[0]}:{aef_id[0]}") + self.publish_ops.publish_message("internal-messages", f"provider-removed:{aef_id[0]}:{apf_id[0]}") return make_response(object=out, status=204) except Exception as e: diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py index 1d67744d..54b2e0e6 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/controllers/default_controller.py @@ -79,6 +79,7 @@ def apf_id_service_apis_service_api_id_delete(service_api_id, apf_id): # noqa: if res.status_code == 204: current_app.logger.info("Removed service published") publisher_ops.publish_message("events", "SERVICE_API_UNAVAILABLE") + publisher_ops.publish_message("internal-messages", f"service-removed:{service_api_id}") return res diff --git a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/consumer_messager.py b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/consumer_messager.py index 49666f01..8108f450 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/consumer_messager.py +++ b/services/TS29222_CAPIF_Publish_Service_API/published_apis/core/consumer_messager.py @@ -20,9 +20,9 @@ def listen(self): current_app.logger.info("Listening publish messages") for raw_message in self.p.listen(): if raw_message["type"] == "message" and raw_message["channel"].decode('utf-8') == "internal-messages": - message, *apf_id = raw_message["data"].decode('utf-8').split(":") + message, *ids = raw_message["data"].decode('utf-8').split(":") if message == "provider-removed": - self.security_ops.delete_intern_service(apf_id[0]) + self.security_ops.delete_intern_service(ids[1]) diff --git a/services/TS29222_CAPIF_Security_API/capif_security/core/consumer_messager.py b/services/TS29222_CAPIF_Security_API/capif_security/core/consumer_messager.py index a9f8293e..65f8ac62 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/core/consumer_messager.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/core/consumer_messager.py @@ -22,9 +22,10 @@ def listen(self): if raw_message["type"] == "message" and raw_message["channel"].decode('utf-8') == "internal-messages": message, *ids = raw_message["data"].decode('utf-8').split(":") if message == "invoker-removed": - self.security_ops.delete_intern_servicesecurity(ids[0]) - if message == "provider-removed": - self.security_ops.update_intern_servicesecurity(ids[1]) + self.security_ops.delete_intern_servicesecurity(ids[1]) + if message == "provider-removed" or message == "service-removed": + self.security_ops.update_intern_servicesecurity(ids[0]) + diff --git a/services/TS29222_CAPIF_Security_API/capif_security/core/internal_security_ops.py b/services/TS29222_CAPIF_Security_API/capif_security/core/internal_security_ops.py index 8195ecd8..d531f79f 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/core/internal_security_ops.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/core/internal_security_ops.py @@ -12,17 +12,17 @@ def delete_intern_servicesecurity(self, api_invoker_id): mycol.delete_many(my_query) current_app.logger.info("Removed security context") - def update_intern_servicesecurity(self, aef_id): + def update_intern_servicesecurity(self, id): current_app.logger.info("Provider Removed, updating security context") security_col = self.db.get_col_by_name(self.db.security_info) - security_contexts = security_col.find({"security_info.aef_id":aef_id}) + + security_contexts = security_col.find({"$or":[{"security_info.aef_id":id}, {"security_info.api_id":id}]}) for security_context in security_contexts: - new_security_info = [info for info in security_context["security_info"] if info["aef_id"]!=aef_id] + new_security_info = [info for info in security_context["security_info"] if info["aef_id"]!=id and info["api_id"] != id] security_context["security_info"] = new_security_info - security_col.update_one({'api_invoker_id':security_context["api_invoker_id"]}, {"$set":security_context}) current_app.logger.info("Updated security context") \ No newline at end of file From a23211719a68576e4785f47ba4f1194286726ef4 Mon Sep 17 00:00:00 2001 From: nacho Date: Fri, 3 Mar 2023 18:15:10 +0100 Subject: [PATCH 4/7] remove superadmin role --- services/nginx/nginx.conf | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/services/nginx/nginx.conf b/services/nginx/nginx.conf index 3facf51d..283fdfac 100644 --- a/services/nginx/nginx.conf +++ b/services/nginx/nginx.conf @@ -14,28 +14,28 @@ http { } map "$request_method:$uri:$ssl_client_s_dn_cn" $invoker_error_message { default 'SUCCESS'; - "~*(PUT|DELETE):.*:(?!(invoker|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; + "~*(PUT|DELETE):.*:(?!(invoker))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $provider_error_message { default 'SUCCESS'; - "~*(PUT|DELETE|PATCH):.*:(?!(amf|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be amf"}'; + "~*(PUT|DELETE|PATCH):.*:(?!(amf))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be amf"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $publish_error_message { default 'SUCCESS'; - "~*.*:.*:(?!(apf|ccf|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; + "~*.*:.*:(?!(apf|ccf))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $discover_error_message { default 'SUCCESS'; - "~*.*:.*:(?!(invoker|ccf|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; + "~*.*:.*:(?!(invoker|ccf))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"User not authorized", "cause":"Certificate not authorized"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $security_error_message { default 'SUCCESS'; - "~*DELETE:.*:(?!(aef|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; - "~*PUT:.*:(?!(invoker|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; - "~*GET:.*:(?!(aef|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; - "~*POST:.*/update:(?!(invoker|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; - "~*POST:.*/delete:(?!(aef|superadmin))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; - "~*POST:.*/token:(?!(invoker|superadmin))(.*)" '{"error":"unauthorized_client", "error_description":"Role not authorized for this API route"}'; + "~*DELETE:.*:(?!(aef))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; + "~*PUT:.*:(?!(invoker))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; + "~*GET:.*:(?!(aef))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; + "~*POST:.*/update:(?!(invoker))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; + "~*POST:.*/delete:(?!(aef))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; + "~*POST:.*/token:(?!(invoker))(.*)" '{"error":"unauthorized_client", "error_description":"Role not authorized for this API route"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $events_error_message { default 'SUCCESS'; From f30ced2eac7ad16ebd68af287e0b01b1611409c1 Mon Sep 17 00:00:00 2001 From: nacho Date: Fri, 3 Mar 2023 18:23:25 +0100 Subject: [PATCH 5/7] fix error remove security context --- .../capif_security/core/consumer_messager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/TS29222_CAPIF_Security_API/capif_security/core/consumer_messager.py b/services/TS29222_CAPIF_Security_API/capif_security/core/consumer_messager.py index 65f8ac62..cd8b22dd 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/core/consumer_messager.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/core/consumer_messager.py @@ -22,7 +22,7 @@ def listen(self): if raw_message["type"] == "message" and raw_message["channel"].decode('utf-8') == "internal-messages": message, *ids = raw_message["data"].decode('utf-8').split(":") if message == "invoker-removed": - self.security_ops.delete_intern_servicesecurity(ids[1]) + self.security_ops.delete_intern_servicesecurity(ids[0]) if message == "provider-removed" or message == "service-removed": self.security_ops.update_intern_servicesecurity(ids[0]) From 812b289142ec4cec632aff8439ca311e6634f7a6 Mon Sep 17 00:00:00 2001 From: nacho Date: Mon, 6 Mar 2023 11:05:45 +0100 Subject: [PATCH 6/7] Update README --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 42c6411d..fb851b9b 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ - [CAPIF Tool Release 2.0](#capif-tool-release-20) - [CAPIF Tool Release 2.1](#capif-tool-release-21) - [CAPIF Tool Release 3.0](#capif-tool-release-30) +- [CAPIF Tool Release 3.1](#capif-tool-release-31) # Repository structure @@ -243,6 +244,13 @@ Changes at Services: * Query and retrieve service API invocation logs stored on the CAPIF core function. +# CAPIF Tool Release 3.1 + +* Delete a service automatically if the provider that contains the APF that published it is deleted +* Clear the security context of an invoker automatically if the invoker is deleted +* Delete automatically the entry in the security info of the security context if the provider that has the aef that published the service is deleted +* Delete automatically the entry in the security info of the security context if the service on which that context was created is deleted + Changes at Tests: * **New common scenarios** in order to make easy to describe a test. * New Test plan definition format. From c8ee1b79a198aa2d4443f200493873da4afeb265 Mon Sep 17 00:00:00 2001 From: nacho Date: Tue, 7 Mar 2023 15:06:28 +0100 Subject: [PATCH 7/7] update README, set versionns of library, remove unnused librarys and fix nginx conf --- README.md | 14 +++++++------- .../requirements.txt | 10 +++++----- .../requirements.txt | 9 +++++---- .../TS29222_CAPIF_Auditing_API/requirements.txt | 5 ++--- .../requirements.txt | 4 ++-- .../capif_events/__main__.py | 4 +--- .../TS29222_CAPIF_Events_API/requirements.txt | 12 ++++++------ .../requirements.txt | 6 +++--- .../requirements.txt | 8 ++++---- .../capif_security/__main__.py | 3 --- .../TS29222_CAPIF_Security_API/requirements.txt | 12 +++++------- services/nginx/nginx.conf | 16 ++++++++-------- 12 files changed, 48 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index fb851b9b..bdf1948c 100644 --- a/README.md +++ b/README.md @@ -244,13 +244,6 @@ Changes at Services: * Query and retrieve service API invocation logs stored on the CAPIF core function. -# CAPIF Tool Release 3.1 - -* Delete a service automatically if the provider that contains the APF that published it is deleted -* Clear the security context of an invoker automatically if the invoker is deleted -* Delete automatically the entry in the security info of the security context if the provider that has the aef that published the service is deleted -* Delete automatically the entry in the security info of the security context if the service on which that context was created is deleted - Changes at Tests: * **New common scenarios** in order to make easy to describe a test. * New Test plan definition format. @@ -258,6 +251,13 @@ Changes at Tests: * Complete code refactor of all tests * Complete test plan review, including all services (except auditing and logging) +# CAPIF Tool Release 3.1 + +* Delete a service automatically if the provider that contains the APF that published it is deleted +* Clear the security context of an invoker automatically if the invoker is deleted +* Delete automatically the entry in the security info of the security context if the provider that has the aef that published the service is deleted +* Delete automatically the entry in the security info of the security context if the service on which that context was created is deleted + diff --git a/services/TS29222_CAPIF_API_Invoker_Management_API/requirements.txt b/services/TS29222_CAPIF_API_Invoker_Management_API/requirements.txt index 86d08f7b..de9d2229 100644 --- a/services/TS29222_CAPIF_API_Invoker_Management_API/requirements.txt +++ b/services/TS29222_CAPIF_API_Invoker_Management_API/requirements.txt @@ -4,8 +4,8 @@ python_dateutil >= 2.6.0 setuptools >= 21.0.0 Flask == 2.0.3 pymongo == 4.0.1 -flask_jwt_extended -pyopenssl -rfc3987 -redis -flask_executor \ No newline at end of file +flask_jwt_extended == 4.4.4 +pyopenssl == 23.0.0 +rfc3987 == 1.3.8 +redis == 4.5.1 +flask_executor == 1.0.0 \ No newline at end of file diff --git a/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt b/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt index edd13c6f..84332fb4 100644 --- a/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt +++ b/services/TS29222_CAPIF_API_Provider_Management_API/requirements.txt @@ -4,8 +4,9 @@ python_dateutil >= 2.6.0 setuptools >= 21.0.0 Flask == 2.0.3 pymongo == 4.0.1 -redis -flask_jwt_extended -flask_executor -pyopenssl +redis == 4.5.1 +flask_executor == 1.0.0 +flask_jwt_extended == 4.4.4 +pyopenssl == 23.0.0 +rfc3987 == 1.3.8 diff --git a/services/TS29222_CAPIF_Auditing_API/requirements.txt b/services/TS29222_CAPIF_Auditing_API/requirements.txt index 45c243e3..ec07ff82 100644 --- a/services/TS29222_CAPIF_Auditing_API/requirements.txt +++ b/services/TS29222_CAPIF_Auditing_API/requirements.txt @@ -5,6 +5,5 @@ setuptools >= 21.0.0 Flask == 2.0.3 pymongo == 4.0.1 elasticsearch == 8.4.3 -flask_jwt_extended -pyopenssl -flask-mqtt +flask_jwt_extended == 4.4.4 +pyopenssl == 23.0.0 diff --git a/services/TS29222_CAPIF_Discover_Service_API/requirements.txt b/services/TS29222_CAPIF_Discover_Service_API/requirements.txt index d348641b..f815469f 100644 --- a/services/TS29222_CAPIF_Discover_Service_API/requirements.txt +++ b/services/TS29222_CAPIF_Discover_Service_API/requirements.txt @@ -4,5 +4,5 @@ python_dateutil >= 2.6.0 setuptools >= 21.0.0 Flask == 2.0.3 pymongo == 4.0.1 -flask_jwt_extended -pyopenssl \ No newline at end of file +flask_jwt_extended == 4.4.4 +pyopenssl == 23.0.0 diff --git a/services/TS29222_CAPIF_Events_API/capif_events/__main__.py b/services/TS29222_CAPIF_Events_API/capif_events/__main__.py index ef555ce5..96c7a164 100644 --- a/services/TS29222_CAPIF_Events_API/capif_events/__main__.py +++ b/services/TS29222_CAPIF_Events_API/capif_events/__main__.py @@ -16,7 +16,6 @@ from multiprocessing import Process from threading import Thread from flask_executor import Executor -from flask_apscheduler import APScheduler from logging.handlers import RotatingFileHandler @@ -61,8 +60,7 @@ def verbose_formatter(): configure_logging(app.app) executor = Executor(app.app) subscriber = Subscriber() -scheduler = APScheduler() -scheduler.init_app(app.app) + @app.app.before_first_request def create_listener_message(): diff --git a/services/TS29222_CAPIF_Events_API/requirements.txt b/services/TS29222_CAPIF_Events_API/requirements.txt index 91e31cef..279753e4 100644 --- a/services/TS29222_CAPIF_Events_API/requirements.txt +++ b/services/TS29222_CAPIF_Events_API/requirements.txt @@ -4,9 +4,9 @@ python_dateutil >= 2.6.0 setuptools >= 21.0.0 Flask == 2.0.3 pymongo == 4.0.1 -flask_jwt_extended -pyopenssl -rfc3987 -redis -flask_executor -Flask-APScheduler +flask_jwt_extended == 4.4.4 +pyopenssl == 23.0.0 +rfc3987 == 1.3.8 +redis == 4.5.1 +flask_executor == 1.0.0 + diff --git a/services/TS29222_CAPIF_Logging_API_Invocation_API/requirements.txt b/services/TS29222_CAPIF_Logging_API_Invocation_API/requirements.txt index 45c243e3..203f4fad 100644 --- a/services/TS29222_CAPIF_Logging_API_Invocation_API/requirements.txt +++ b/services/TS29222_CAPIF_Logging_API_Invocation_API/requirements.txt @@ -5,6 +5,6 @@ setuptools >= 21.0.0 Flask == 2.0.3 pymongo == 4.0.1 elasticsearch == 8.4.3 -flask_jwt_extended -pyopenssl -flask-mqtt +flask_jwt_extended == 4.4.4 +pyopenssl == 23.0.0 + diff --git a/services/TS29222_CAPIF_Publish_Service_API/requirements.txt b/services/TS29222_CAPIF_Publish_Service_API/requirements.txt index e7e09b43..acf2b9c8 100644 --- a/services/TS29222_CAPIF_Publish_Service_API/requirements.txt +++ b/services/TS29222_CAPIF_Publish_Service_API/requirements.txt @@ -4,8 +4,8 @@ python_dateutil >= 2.6.0 setuptools >= 21.0.0 Flask == 2.0.3 pymongo == 4.0.1 -flask_jwt_extended -flask_executor -pyopenssl -redis +flask_jwt_extended == 4.4.4 +pyopenssl == 23.0.0 +redis == 4.5.1 +flask_executor == 1.0.0 diff --git a/services/TS29222_CAPIF_Security_API/capif_security/__main__.py b/services/TS29222_CAPIF_Security_API/capif_security/__main__.py index e98259b9..d24b496d 100644 --- a/services/TS29222_CAPIF_Security_API/capif_security/__main__.py +++ b/services/TS29222_CAPIF_Security_API/capif_security/__main__.py @@ -8,7 +8,6 @@ from .core.consumer_messager import Subscriber from threading import Thread from flask_executor import Executor -from flask_apscheduler import APScheduler from logging.handlers import RotatingFileHandler import sys @@ -56,8 +55,6 @@ def main(): JWTManager(app.app) subscriber = Subscriber() - scheduler = APScheduler() - scheduler.init_app(app.app) configure_logging(app.app) executor = Executor(app.app) diff --git a/services/TS29222_CAPIF_Security_API/requirements.txt b/services/TS29222_CAPIF_Security_API/requirements.txt index 0854cc80..578188ff 100644 --- a/services/TS29222_CAPIF_Security_API/requirements.txt +++ b/services/TS29222_CAPIF_Security_API/requirements.txt @@ -4,10 +4,8 @@ python_dateutil >= 2.6.0 setuptools >= 21.0.0 Flask == 2.0.3 pymongo == 4.0.1 -flask_jwt_extended -pyjwt -rfc3987 -redis -pyopenssl -flask_executor -Flask-APScheduler \ No newline at end of file +flask_jwt_extended == 4.4.4 +pyopenssl == 23.0.0 +rfc3987 == 1.3.8 +redis == 4.5.1 +flask_executor == 1.0.0 diff --git a/services/nginx/nginx.conf b/services/nginx/nginx.conf index 283fdfac..2599f779 100644 --- a/services/nginx/nginx.conf +++ b/services/nginx/nginx.conf @@ -14,11 +14,11 @@ http { } map "$request_method:$uri:$ssl_client_s_dn_cn" $invoker_error_message { default 'SUCCESS'; - "~*(PUT|DELETE):.*:(?!(invoker))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; + "~*(PUT|DELETE):.*:(?!invoker)(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $provider_error_message { default 'SUCCESS'; - "~*(PUT|DELETE|PATCH):.*:(?!(amf))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be amf"}'; + "~*(PUT|DELETE|PATCH):.*:(?!amf)(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be amf"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $publish_error_message { default 'SUCCESS'; @@ -30,12 +30,12 @@ http { } map "$request_method:$uri:$ssl_client_s_dn_cn" $security_error_message { default 'SUCCESS'; - "~*DELETE:.*:(?!(aef))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; - "~*PUT:.*:(?!(invoker))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; - "~*GET:.*:(?!(aef))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; - "~*POST:.*/update:(?!(invoker))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; - "~*POST:.*/delete:(?!(aef))(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; - "~*POST:.*/token:(?!(invoker))(.*)" '{"error":"unauthorized_client", "error_description":"Role not authorized for this API route"}'; + "~*DELETE:.*:(?!aef)(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; + "~*PUT:.*:(?!invoker)(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; + "~*GET:.*:(?!aef)(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; + "~*POST:.*/update:(?!invoker)(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be invoker"}'; + "~*POST:.*/delete:(?!aef)(.*)" '{"status":401, "title":"Unauthorized" ,"detail":"Role not authorized for this API route", "cause":"User role must be aef"}'; + "~*POST:.*/token:(?!invoker)(.*)" '{"error":"unauthorized_client", "error_description":"Role not authorized for this API route"}'; } map "$request_method:$uri:$ssl_client_s_dn_cn" $events_error_message { default 'SUCCESS';