diff --git a/app/api/policy_eval_api.py b/app/api/policy_eval_api.py index 47c6dea036fba215aab87646f15c9dd9bd2ad366..853a0d5b6a984557f0e51c30dab6283abdc37395 100644 --- a/app/api/policy_eval_api.py +++ b/app/api/policy_eval_api.py @@ -35,6 +35,7 @@ from starlette.status import ( sys.path.append(os.path.abspath("..")) import opa +import safe from auth import auth @@ -118,6 +119,13 @@ def evaluate_policy( logger = logging.getLogger(__name__) response.headers["X-Correlation-ID"] = context["correlation_id"] + if not safe.is_safe_policy_id(policy_id): + safe_policy_id = safe.safe_encode(policy_id) + logger.critical(f"Error Invalid policy_id: {safe_policy_id}") + raise HTTPException( + status_code=HTTP_400_BAD_REQUEST, detail=safe.BAD_REQUEST_DETAIL + ) + # not expected with our current dataauthz.rego if policy_id.endswith(".rego"): policy_id = policy_id.removesuffix(".rego") diff --git a/app/api/policy_read_api.py b/app/api/policy_read_api.py index a319b848314bb84ec77bed99705f1e868afccf6a..bac6cdc792fa2b0906c9b982fc7e2e27089d2363 100644 --- a/app/api/policy_read_api.py +++ b/app/api/policy_read_api.py @@ -35,6 +35,7 @@ from opa_response import OpaResponse sys.path.append(os.path.abspath("..")) import conf import opa +import safe from auth import auth import correlation @@ -148,13 +149,18 @@ def fetch_a_policy( logger = logging.getLogger(__name__) response.headers["X-Correlation-ID"] = context["correlation_id"] + if not safe.is_safe_policy_id(policy_id): + safe_policy_id = safe.safe_encode(policy_id) + logger.critical(f"Error Invalid policy_id: {safe_policy_id}") + raise HTTPException( + status_code=HTTP_400_BAD_REQUEST, detail=safe.BAD_REQUEST_DETAIL + ) + cloud_provider = os.environ.get("CLOUD_PROVIDER") if cloud_provider is None: # Help support MOCK testing opa_response = OpaResponse() - logger.critical( - f"Error: CLOUD_PROVIDER ENV VAR not set / Mocking results for /policies/{policy_id}" - ) + opa_response.message = f"MOCK Policy {policy_id} added to OPA" opa_response.ok = False opa_response.json = {"result": {}} @@ -204,6 +210,13 @@ def fetch_instance_policy( logger = logging.getLogger(__name__) response.headers["X-Correlation-ID"] = context["correlation_id"] + if not safe.is_safe_policy_id(policy_id): + safe_policy_id = safe.safe_encode(policy_id) + logger.critical(f"Error Invalid policy_id: {safe_policy_id}") + raise HTTPException( + status_code=HTTP_400_BAD_REQUEST, detail=safe.BAD_REQUEST_DETAIL + ) + cloud_provider = os.environ.get("CLOUD_PROVIDER") if cloud_provider is None: # Help support MOCK testing @@ -271,6 +284,13 @@ def fetch_partition_policy_directly_from_opa( detail="Provided data partition id does not correspond to provided policy id", ) + if not safe.is_safe_policy_id(policy_id): + safe_policy_id = safe.safe_encode(policy_id) + logger.critical(f"Error Invalid policy_id: {safe_policy_id}") + raise HTTPException( + status_code=HTTP_400_BAD_REQUEST, detail=safe.BAD_REQUEST_DETAIL + ) + cloud_provider = os.environ.get("CLOUD_PROVIDER") if cloud_provider is None: # Help support MOCK testing diff --git a/app/api/policy_update_api.py b/app/api/policy_update_api.py index 1fe456adfac7410f274d52f55909934fdf09e29d..3f787e8780b90e277bfdb729a6fddc58a3584311 100644 --- a/app/api/policy_update_api.py +++ b/app/api/policy_update_api.py @@ -40,6 +40,7 @@ from opa_response import OpaResponse sys.path.append(os.path.abspath("..")) import conf import opa +import safe from auth import auth from bundles import bundle import correlation @@ -157,8 +158,17 @@ def delete_partition_policy( detail="Policy ID should end with a .rego", ) + if not safe.is_safe_policy_id(policy_id): + safe_policy_id = safe.safe_encode(policy_id) + logger.critical(f"Error Invalid policy_id: {safe_policy_id}") + raise HTTPException( + status_code=HTTP_400_BAD_REQUEST, detail=safe.BAD_REQUEST_DETAIL + ) + cloud_provider = os.environ.get("CLOUD_PROVIDER") + pol_id = f"osdu/partition/{data_partition}/{policy_id}" + if cloud_provider is None: # Help support MOCK testing result = OpaResponse() @@ -323,6 +333,13 @@ def create_or_update_partition_policy( detail="Policy ID should end with a .rego", ) + if not safe.is_safe_policy_id(policy_id): + safe_policy_id = safe.safe_encode(policy_id) + logger.critical(f"Error Invalid policy_id: {safe_policy_id}") + raise HTTPException( + status_code=HTTP_400_BAD_REQUEST, detail=safe.BAD_REQUEST_DETAIL + ) + contents = file.file.read() if not bundle.package_name_ok(data_partition, policy_id, contents): diff --git a/app/api/tenant_api.py b/app/api/tenant_api.py index 30263f8e90a929aed1013f33095c5a2ba0672863..8009ff7dbc1db3c726290e13647f8e8c7f374d14 100644 --- a/app/api/tenant_api.py +++ b/app/api/tenant_api.py @@ -9,6 +9,7 @@ import correlation import ruamel.yaml from kubernetes.client.models import V1ConfigMap, V1ObjectMeta from pydantic import BaseModel +import base64 from starlette.status import ( HTTP_202_ACCEPTED, @@ -131,6 +132,29 @@ def update_tenant( logger = logging.getLogger(__name__) response.headers["X-Correlation-ID"] = context["correlation_id"] + if not service.replace("_", "").isalnum(): + safe_service = base64.b64encode(service.encode("UTF-8")) + logger.critical(f"Error Invalid {safe_service}") + raise HTTPException(status_code=HTTP_400_BAD_REQUEST, detail="Invalid service") + + if not polling_min_delay_seconds.isdigit(): + safe_polling_min_delay_seconds = base64.b64encode( + polling_min_delay_seconds.encode("UTF-8") + ) + logger.critical(f"Error Invalid {safe_polling_min_delay_seconds}") + raise HTTPException( + status_code=HTTP_400_BAD_REQUEST, detail="Invalid polling_min_delay_seconds" + ) + + if not polling_max_delay_seconds.isdigit(): + safe_polling_max_delay_seconds = base64.b64encode( + polling_max_delay_seconds.encode("UTF-8") + ) + logger.critical(f"Error Invalid {safe_polling_max_delay_seconds}") + raise HTTPException( + status_code=HTTP_400_BAD_REQUEST, detail="Invalid polling_max_delay_seconds" + ) + logger.info( f"service: {service}, polling_min_delay_seconds: {polling_min_delay_seconds}, polling_max_delay_seconds: {polling_max_delay_seconds}" ) diff --git a/app/api/validate_api.py b/app/api/validate_api.py index e2b12c9ac80eacd887b9b49881f579f3348265be..f7420076a359a59f09d29e65332711a4f82e3cc1 100644 --- a/app/api/validate_api.py +++ b/app/api/validate_api.py @@ -8,6 +8,7 @@ import correlation from bundles import bundle from string import Template import hashlib +import safe from pydantic import BaseModel @@ -61,6 +62,13 @@ def validate_policy( detail="Policy ID should end with a .rego", ) + if not safe.is_safe_policy_id(policy_id): + safe_policy_id = safe.safe_encode(policy_id) + logger.critical(f"Error Invalid policy_id: {safe_policy_id}") + raise HTTPException( + status_code=HTTP_400_BAD_REQUEST, detail=safe.BAD_REQUEST_DETAIL + ) + contents = file.file.read() if template: @@ -113,6 +121,13 @@ def verify_policy_with_opa( detail="Policy ID should end with a .rego", ) + if not safe.is_safe_policy_id(policy_id): + safe_policy_id = safe.safe_encode(policy_id) + logger.critical(f"Error Invalid policy_id: {safe_policy_id}") + raise HTTPException( + status_code=HTTP_400_BAD_REQUEST, detail=safe.BAD_REQUEST_DETAIL + ) + data_partition = auth_data.data_partition_id headers = CaseInsensitiveDict() diff --git a/app/safe.py b/app/safe.py new file mode 100644 index 0000000000000000000000000000000000000000..08ddee390240cc149eb64a1c9deb4a956659279e --- /dev/null +++ b/app/safe.py @@ -0,0 +1,11 @@ +import base64 + + +def is_safe_policy_id(policy_id: str) -> bool: + return policy_id.replace("_", "").replace(".", "").replace("/","").replace("-","").isalnum() + + +def safe_encode(policy_id: str) -> str: + return base64.b64encode(policy_id.encode("UTF-8")) + +BAD_REQUEST_DETAIL="Invalid Policy ID" \ No newline at end of file diff --git a/search_eando.py b/search_eando.py index 8b54b25fb1d244fa46b128541957039c178226be..67aef90e9add972da8fcabb8c42fb76c99572566 100644 --- a/search_eando.py +++ b/search_eando.py @@ -4,33 +4,33 @@ import requests from rego import ast, walk # Load input data -inputfile = open('search_input.json') -inputdata = json.load(inputfile) +inputfile = open("search_input.json") +inputdata = json.load(inputfile) opaurl = "http://localhost:8181" -#datapath = "http://localhost:8181/v1/data" +# datapath = "http://localhost:8181/v1/data" policypath = opaurl + "/v1/policies" -#get all policies +# get all policies resp = requests.get(policypath) policies = resp.json() -#print(policies) +# print(policies) -#resp = requests.post(compilepath) +# resp = requests.post(compilepath) compilepath = opaurl + "/v1/compile" respqry = requests.post(compilepath, data=json.dumps(inputdata)) # Load the resulting set of query ASTs out of the JSON response. result = respqry.json()["result"]["queries"] -#result = respqry.json() -#print(json.dumps(result, indent=4) -#print(result) +# result = respqry.json() +# print(json.dumps(result, indent=4) +# print(result) qs = ast.QuerySet.from_data(result) print(qs) # Pretty print the ASTs. -#walk.pretty_print(qs) +# walk.pretty_print(qs)