commit ecd21287ece71dff1173785feabb5d02217e5936 Author: Cristiano Hoshikawa Date: Tue Aug 13 07:59:21 2024 -0300 first commit diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..0a8642f --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Zeppelin ignored files +/ZeppelinRemoteNotebooks/ diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..a346fd7 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..8c5b822 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/oci_api_gw_custom_auth.iml b/.idea/oci_api_gw_custom_auth.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/oci_api_gw_custom_auth.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/config b/config new file mode 100644 index 0000000..2400c04 --- /dev/null +++ b/config @@ -0,0 +1,6 @@ +[DEFAULT] +user=ocid1.user.oc1..aaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +fingerprint=xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx +key_file=oci_api_key.pem +tenancy=ocid1.tenancy.oc1..aaaaaaaaxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +region=us-ashburn-1 diff --git a/config.json b/config.json new file mode 100644 index 0000000..2c4bb1d --- /dev/null +++ b/config.json @@ -0,0 +1,12 @@ +{ + "ClientId" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "ClientSecret" : "8xxxxxxxx-xxxx-xxxx-xxxxx-xxxxxxxxxxxxxxxx", + "BaseUrl" : "https://idcs-xxxxxxxxxxxxxxxxxxxxx.identity.oraclecloud.com", + "AudienceServiceUrl" : "https://idcs-xxxxxxxxxxxxxxxxxxxxxxxx.identity.oraclecloud.com", + "scope" : "xxxxxxxxxxxxxxxxxxxxxxx.apigateway.us-ashburn-1.oci.customer-oci.com/super-scope", + "TokenIssuer" : "https://identity.oraclecloud.com", + "redirectURL": "http://localhost:8000/callback", + "logoutSufix":"/oauth2/v1/userlogout", + "LogLevel":"INFO", + "ConsoleLog":"True" +} diff --git a/func.py b/func.py new file mode 100644 index 0000000..70f969c --- /dev/null +++ b/func.py @@ -0,0 +1,184 @@ +import base64 +import json +import io +from fdk import response +import oci +import requests +import time +from openapi_schema_validator import validate +import os +import ast +from bravado_core.spec import Spec +from bravado_core.validate import validate_object +from datetime import datetime +from random import randrange + +#### IDCS Routines +#### https://docs.oracle.com/en/learn/apigw-modeldeployment/index.html#introduction +#### https://docs.oracle.com/en/learn/migrate-api-to-api-gateway/#introduction + +def base64_string(clientID, secretID): + auth = clientID + ":" + secretID + auth_bytes = auth.encode("ascii") + auth_base64_bytes = base64.b64encode(auth_bytes) + auth_base64_message = auth_base64_bytes.decode("ascii") + return auth_base64_message + +def auth_idcs(token, url, clientID, secretID): + url = url + "/oauth2/v1/introspect" + + auth_base64_message = base64_string(clientID, secretID) + + headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Authorization': 'Basic ' + auth_base64_message + } + + payload = "token=" + token + + response = requests.request("POST", url, headers=headers, data=payload) + return response + +def conta_items(dictData): + contagem = 0 + for item in dictData: + try: + if type(dictData[item]) == list: + contagem += len(dictData[item]) + else: + if not type(dictData[item]) == str: + contagem += conta_items(dictData[item]) + except: + print("item = not string") + return contagem + +def count_attributes(json_data): + count = 0 + for key, value in json_data.items(): + count += 1 + if isinstance(value, dict): + count += count_attributes(value) + return count + +def handler(ctx, data: io.BytesIO = None): + config = oci.config.from_file("config") + logging = oci.loggingingestion.LoggingClient(config) + + # functions context variables + app_context = dict(ctx.Config()) + + jsonData = "" + + try: + header = json.loads(data.getvalue().decode('utf-8'))["data"] + + # IDCS Validation + url = "https://idcs-xxxxxxxxxxxxxxxxxxxxxxxxxxxxx.identity.oraclecloud.com" + ClientId = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + ClientSecret = "8xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" + + oic_clientId = "FXXXXXXXXXXXXXXXXXXXXXXXXXXX_APPID" + oic_clientSecret = "xxxxxxxxxx-xxxxx-xxxxx-xxxx-xxxxxxxxxxxxx" + auth_base64_message = base64_string(oic_clientId, oic_clientSecret) + + # JSON Items counter + jsonData = dict(json.loads(data.getvalue().decode('utf-8')).get("data"))["body"] + jsonData = dict(json.loads(jsonData)) + c = count_attributes(jsonData) + if (c > 12): + rdata = json.dumps({ + "active": False, + "context": { + "status_code": 401, + "message": "JSON exception", + "error": "JSON exception", + }}) + + return response.Response( + ctx, + status_code=401, + response_data=rdata + ) + + try: + body = dict(json.loads(data.getvalue().decode('utf-8')).get("data"))["body"] + body = json.loads(body) + except: + body = None + + # header values + access_token = header["token"] + + authorization = auth_idcs(access_token, url, ClientId, ClientSecret) + try: + if (authorization.json().get("active") != True): + return response.Response( + ctx, + status_code=401, + response_data=json.dumps({"active": False, "wwwAuthenticate": jsonData}) + ) + except(Exception) as ex1: + jsonData = 'error parsing json payload(2): ' + str(ex1) + put_logs_response = logging.put_logs( + log_id="ocid1.log.oc1.iad.amaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + put_logs_details=oci.loggingingestion.models.PutLogsDetails( + specversion="EXAMPLE-specversion-Value", + log_entry_batches=[ + oci.loggingingestion.models.LogEntryBatch( + entries=[ + oci.loggingingestion.models.LogEntry( + data="error(a): " + jsonData, + id="ocid1.test.oc1..00000001.EXAMPLE-id-Value")], + source="EXAMPLE-source-Value", + type="EXAMPLE-type-Value")])) + rdata = json.dumps({ + "active": False, + "context": { + "status_code": 401, + "message": "Unauthorized", + "body": body, + "body_schema_validation": json.dumps(body_schema_validation), + "error": str(ex1) + }}) + + return response.Response( + ctx, + status_code=401, + response_data=rdata + ) + + rdata = json.dumps({ + "active": True, + "context": { + "body": body, + "authorization_idcs": "Basic " + auth_base64_message + }}) + + return response.Response( + ctx, response_data=rdata, + status_code=200, + headers={"Content-Type": "application/json", "body": json.dumps(body)} + ) + + except(Exception) as ex: + jsonData = 'error parsing json payload(1): ' + str(ex) + put_logs_response = logging.put_logs( + log_id="ocid1.log.oc1.iad.amaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + put_logs_details=oci.loggingingestion.models.PutLogsDetails( + specversion="EXAMPLE-specversion-Value", + log_entry_batches=[ + oci.loggingingestion.models.LogEntryBatch( + entries=[ + oci.loggingingestion.models.LogEntry( + data="error(c): " + jsonData, + id="ocid1.test.oc1..00000001.EXAMPLE-id-Value")], + source="EXAMPLE-source-Value", + type="EXAMPLE-type-Value")])) + + pass + + return response.Response( + ctx, + status_code=401, + response_data=json.dumps({"active": False, "wwwAuthenticate": jsonData}) + ) diff --git a/func.yaml b/func.yaml new file mode 100644 index 0000000..db7dbe5 --- /dev/null +++ b/func.yaml @@ -0,0 +1,8 @@ +schema_version: 20180708 +name: auth-api +version: 0.0.723 +runtime: python +build_image: fnproject/python:3.9-dev +run_image: fnproject/python:3.9 +entrypoint: /python/bin/fdk /function/func.py handler +memory: 256 diff --git a/oci_api_key.pem b/oci_api_key.pem new file mode 100644 index 0000000..48a1727 --- /dev/null +++ b/oci_api_key.pem @@ -0,0 +1,21 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +MIIEpAIBAAKCAQEAr7/go+lbpX2toGkCfFMX2UD/EKWXt+upllj2o0g43BFQ2JVJ +hZsTonAFY2y20Ql6v/rvYpTMsiUvMVI/Jx43jBcPunGHn/asLmfLZg== +-----END RSA PRIVATE KEY----- diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..4b612e3 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,10 @@ +fdk>=0.1.54 +requests +oci +cryptography +six +PyJWT +py3_lru_cache +simplejson +openapi-schema-validator +bravado-core