def get_AuthToken(cr_id, operator_url, app_config): print(operator_url, cr_id) helpers = Helpers(app_config) print(cr_id) token = get("{}/api/1.3/cr/auth_token/{}".format( operator_url, cr_id)) # TODO Get api path from some config? print(token.url, token.reason, token.status_code, token.text) store_dict = {cr_id: dumps(loads(token.text.encode()))} helpers.storeToken(store_dict) cr_csr = helpers.get_cr_json(cr_id) cr_tool = CR_tool() cr_tool.cr = cr_csr user_id = cr_tool.get_surrogate_id() rs_id = cr_tool.get_rs_id() #req = get("http://service_components:7000/api/1.3/sink_flow/init") #print(req.url, req.status_code, req.content) data = { "cr_id": cr_id, "user_id": user_id, "rs_id": urllib.quote_plus(rs_id) } print(dumps(data, indent=2))
def __init__(self): super(Install_CR, self).__init__() self.helpers = Helpers(current_app.config) self.is_sink = current_app.config["IS_SINK"] self.is_source = current_app.config["IS_SOURCE"] self.operator_url = current_app.config["OPERATOR_URL"] self.db_path = current_app.config["DATABASE_PATH"]
def __init__(self): super(GenerateSurrogateId, self).__init__() keysize = current_app.config["KEYSIZE"] cert_key_path = current_app.config["CERT_KEY_PATH"] self.helpers = Helpers(current_app.config) self.service_key = self.helpers.get_key() self.is_sink = current_app.config["IS_SINK"] self.is_source = current_app.config["IS_SOURCE"] self.service_id = current_app.config["SERVICE_ID"] self.service_url = current_app.config["SERVICE_URL"] self.operator_url = current_app.config["OPERATOR_URL"] self.lock_wait_time = current_app.config["LOCK_WAIT_TIME"]
def __init__(self): super(StoreSLR, self).__init__() config = current_app.config keysize = config["KEYSIZE"] cert_key_path = config["CERT_KEY_PATH"] self.helpers = Helpers(config) self.service_key = self.helpers.get_key() self.protti = self.service_key["prot"] self.headeri = self.service_key["header"] self.service_url = config["SERVICE_URL"] self.operator_url = config["OPERATOR_URL"]
def __init__(self): super(StartServiceLinking, self).__init__() self.helpers = Helpers(current_app.config) self.service_key = self.helpers.get_key() self.is_sink = current_app.config["IS_SINK"] self.is_source = current_app.config["IS_SOURCE"] self.service_url = current_app.config["SERVICE_URL"] self.operator_url = current_app.config["OPERATOR_URL"] self.lock_wait_time = current_app.config["LOCK_WAIT_TIME"] self.parser = reqparse.RequestParser() self.parser.add_argument('code', type=str, help='session code') self.parser.add_argument('operator_id', type=str, help='Operator UUID.') self.parser.add_argument('return_url', type=str, help='Url safe Base64 coded return url.') self.parser.add_argument('surrogate_id', type=str, help="surrogate ID")
class StartServiceLinking(Resource): def __init__(self): super(StartServiceLinking, self).__init__() self.helpers = Helpers(current_app.config) self.service_key = self.helpers.get_key() self.is_sink = current_app.config["IS_SINK"] self.is_source = current_app.config["IS_SOURCE"] self.service_url = current_app.config["SERVICE_URL"] self.operator_url = current_app.config["OPERATOR_URL"] self.lock_wait_time = current_app.config["LOCK_WAIT_TIME"] self.parser = reqparse.RequestParser() self.parser.add_argument('code', type=str, help='session code') self.parser.add_argument('operator_id', type=str, help='Operator UUID.') self.parser.add_argument('return_url', type=str, help='Url safe Base64 coded return url.') self.parser.add_argument('surrogate_id', type=str, help="surrogate ID") # TODO: Verify service_id is unnecessary. #self.parser.add_argument('service_id', type=str, help="Service's ID") # Seems unnecessary to the flow. @error_handler @api_logging def post(self): args = self.parser.parse_args() debug_log.debug("StartServiceLinking got parameter:\n {}".format(args)) data = {"surrogate_id": args["surrogate_id"], "code": args["code"]} sq.task("Link code to generated surrogate_id") self.helpers.add_code_to_surrogate_id(args["code"], args["surrogate_id"]) if self.is_sink: data["token_key"] = self.service_key["pub"] # TODO: Are we implementing according to 1.3 in such way that we have # operator, service, user specific pop keys? sq.send_to("Operator_Components Mgmnt", "Send Operator_Components request to make SLR") endpoint = "/api/1.3/slr/link" # Todo: this needs to be fetched from somewhere result = post("{}{}".format(self.operator_url, endpoint), json=data) debug_log.info("####slr/link reply from operator: {}\n{}".format(result.status_code, result.text)) if result.ok: self.helpers.delete_session(args["code"]) return result.text, 201 elif result.status_code == 500: self.helpers.delete_session(args["code"]) raise DetailedHTTPException(status=500, detail={"msg": "Linking Service has failed due to server side issue."}, title="Could not link Service.") else: self.helpers.delete_session(args["code"]) raise DetailedHTTPException(status=result.status_code, detail={ "msg": "Something went wrong while posting to Operator_SLR for /link", "Error from Operator_SLR": loads(result.text)}, title=result.reason)
class StoreSSR(Resource): def __init__(self): super(StoreSSR, self).__init__() config = current_app.config self.helpers = Helpers(config) self.service_url = config["SERVICE_URL"] @timeme @error_handler @api_logging def post(self): # TODO: This is as naive as it gets, needs some verifications regarding ssr, # or are we leaving this to firewalls, eg. Only this host(operator) can use this endpoint. try: self.helpers.store_ssr_JSON(json=request.json["data"]) endpoint = "/api/1.3/slr/store_ssr" debug_log.info("Posting SLR for storage in Service Mockup") result = post("{}{}".format(self.service_url, endpoint), json=request.json) # Send copy to Service_Components return {"id":request.json["data"]["id"]}, 201 except Exception as e: debug_log.exception(e) raise e
class DebugDataFlow(Resource): def __init__(self): super(DebugDataFlow, self).__init__() self.service_url = current_app.config["SERVICE_URL"] self.own_url = current_app.config["SINK_URL"] self.operator_url = current_app.config["OPERATOR_URL"] self.helpers = Helpers(current_app.config) @error_handler @api_logging def get(self, rs_id): debug_log.info("Got rs_id {} to DebugDataFlow endpoint".format(rs_id)) records = self.helpers.query_db_multiple( "select rs_id, cr_id, slr_id, surrogate_id from cr_storage", ()) #rs_id = debug_log.info( "DB query resulted in following results:\n{}".format(records)) for record in records: rs_id = record[0] cr_id = record[1] tool = CR_tool() tool.cr = self.helpers.get_cr_json(cr_id) role = tool.get_role() debug_log.info("Found role {}".format(role)) if role == "Sink": if record[0] == rs_id: surrogate_id = record[3] payload = { "user_id": surrogate_id, "cr_id": cr_id, "rs_id": urllib.quote_plus(rs_id) } # TODO get the url from, config debug_log.info(dumps(payload, indent=2)) req = requests.post(self.own_url + "/api/1.3/sink_flow/dc", json=payload) return req.content
class Install_CR(Resource): def __init__(self): super(Install_CR, self).__init__() self.helpers = Helpers(current_app.config) self.is_sink = current_app.config["IS_SINK"] self.is_source = current_app.config["IS_SOURCE"] self.operator_url = current_app.config["OPERATOR_URL"] self.db_path = current_app.config["DATABASE_PATH"] @error_handler @api_logging def post(self): debug_log.info("arrived at Install_CR") cr_stuff = request.json sq.activate() sq.task("Install CR/CSR") '''post :return: Returns 202 ''' crt = CR_tool() crt.cr = cr_stuff role = crt.get_role() sq.task("Verify CR format and mandatory fields") if role == "Source" and self.is_source: debug_log.info("Source CR") debug_log.info(dumps(crt.get_CR_payload(), indent=2)) debug_log.info(type(crt.get_CR_payload())) errors = validate_json(source_cr_schema, crt.get_CR_payload()) for e in errors: raise DetailedHTTPException(detail={"msg": "Validating Source CR format and fields failed", "validation_errors": errors}, title="Failure in CR validation", status=400) if role == "Sink" and self.is_sink: debug_log.info("Sink CR") errors = validate_json(sink_cr_schema, crt.get_CR_payload()) for e in errors: raise DetailedHTTPException(detail={"msg": "Validating Sink CR format and fields failed", "validation_errors": errors}, title="Failure in CR validation", status=400) if ((role == "Source" and self.is_source) or (role == "Sink" and self.is_sink)) is False: raise DetailedHTTPException(detail={"msg": "Validating CR format and fields failed." " It is possible CR didn't specify role or that Service is " "configured to be nether sink, source or both"}, title="Failure in CR validation", status=400) debug_log.info(dumps(crt.get_CR_payload(), indent=2)) debug_log.info(dumps(crt.get_CSR_payload(), indent=2)) # SLR includes CR keys which means we need to get key from stored SLR and use it to verify this # 1) Fetch surrogate_id so we can query our database for slr sq.task("Fetch surrogate_id and slr_id from the CR") surr_id = crt.get_surrogate_id() slr_id = crt.get_slr_id() sq.task("Verify SLR is Active for this CR") # Verify SLR is Active: TODO: This could probably return SLR so we don't fetch it second time below. if self.helpers.verify_slr_is_active(slr_id) is False: raise DetailedHTTPException(detail={"msg": "SLR not Active",}, title="Consent Can't be granted with inactive SLR", status=403) debug_log.info("Fetched surr_id({}) and slr_id({})".format(surr_id, slr_id)) sq.task("Verify CR is signed with keys in associated SLR") slrt = SLR_tool() slrt.slr = self.helpers.get_slr(surr_id) verify_is_success = crt.verify_cr(slrt.get_cr_keys()) if verify_is_success: debug_log.info("CR was verified with key from SLR") else: raise DetailedHTTPException(detail={"msg": "Verifying CR failed", }, title="Failure in CR verifying", status=403) sq.task("Verify CSR format and mandatory fields") errors = validate_json(csr_schema, crt.get_CSR_payload()) for e in errors: raise DetailedHTTPException(detail={"msg": "Validating CSR format and fields failed", "validation_errors": errors}, title="Failure in CSR validation", status=400) # 1) CSR has link to CR csr_has_correct_cr_id = crt.cr_id_matches_in_csr_and_cr() if csr_has_correct_cr_id: debug_log.info("Verified CSR links to CR") else: raise DetailedHTTPException(detail={"msg": "Verifying CSR cr_id == CR cr_id failed",}, title="Failure in CSR verifying", status=403) sq.task("Verify CSR is signed with keys in associated SLR") # SLR includes CR keys which means we need to get key from stored SLR and use it to verify this verify_is_success = crt.verify_csr(slrt.get_cr_keys()) if verify_is_success: debug_log.info("CSR was verified with key from SLR") else: raise DetailedHTTPException(detail={"msg": "Verifying CSR failed",}, title="Failure in CSR verifying", status=403) # # Verify CR before we do intense DB lookups # verify_is_success = crt.verify_cr(slrt.get_cr_keys()) # if verify_is_success: # sq.task("Verify CR is issued by authorized party") # debug_log.info("CR was verified with key from SLR") # else: # raise DetailedHTTPException(detail={"msg": "Verifying CR failed",}, # title="Failure in CR verifying") # 2) CSR has link to previous CSR # If prev csr id is null it means this is first time we handle this CR, thus its the first CSR # Check that previous CSR has not been withdrawn or paused # If previous_id is null this step can be ignored. # Else fetch previous_id from db and check the status. sq.task("Verify CSR chain is intact.") prev_csr_id_refers_to_null = crt.get_prev_record_id() == "null" if prev_csr_id_refers_to_null: debug_log.info("prev_csr_id_referred to null as it should.") else: try: last_csr_state = self.helpers.introspection(crt.get_cr_id_from_csr(), self.operator_url) if last_csr_state in ["Active", "Paused"]: raise DetailedHTTPException(detail={"msg":"There is existing CR that is active," " before creating new CR you should change" " status of old accordingly."}) except LookupError as e: debug_log.info("Cr_id({}) doesn't have Active status in its last CSR".format(crt.get_cr_id_from_cr())) raise DetailedHTTPException(detail={"msg": "Verifying CSR previous_id == 'null' failed",}, title="Failure in CSR verifying", status=403) sq.task("Store CR and CSR") store_dict = { "rs_id": crt.get_rs_id(), "csr_id": crt.get_csr_id(), "consent_status": crt.get_consent_status(), "previous_record_id": crt.get_prev_record_id(), "cr_id": crt.get_cr_id_from_cr(), "surrogate_id": surr_id, "slr_id": crt.get_slr_id(), "json": crt.cr["cr"] # possibly store the base64 representation } self.helpers.storeCR_JSON(store_dict) # Remove unused items from dict, csr db doesn't need all of those. store_dict.pop("rs_id", None) store_dict.pop("slr_id", None) store_dict["json"] = crt.cr["csr"] self.helpers.storeCSR_JSON(store_dict) sq.reply_to("OpMgmt", "201 cr_id") if role == "Sink" and self.is_sink: debug_log.info("Requesting auth_token") sq.task("Request AuthToken from Operator") get_AuthToken.delay(crt.get_cr_id_from_cr(), self.operator_url, current_app.config) sq.deactivate() return {"id": crt.get_cr_id_from_cr()}, 201 @error_handler @api_logging def patch(self): # TODO: Currently only Operator actually verifies we're not being fed crap. payload = request.json # Decode payload decoded_payload = base_token_tool.decode_payload(payload["data"]["attributes"]["payload"]) # Create template for StoreCSR_JSON store_dict = { "csr_id": decoded_payload["record_id"], "consent_status": decoded_payload["consent_status"], "previous_record_id": decoded_payload["prev_record_id"], "cr_id": decoded_payload["cr_id"], "surrogate_id": decoded_payload["surrogate_id"], "json": payload["data"]["attributes"] # possibly store the base64 representation } sq.activate() sq.task("Store new CSR into Database.") # Store CSR to database self.helpers.storeCSR_JSON(store_dict) # Forward change to Service # To be implemented..... sq.reply_to("OpMgmt", "201 csr_id") sq.deactivate() return {"id": decoded_payload["record_id"]}, 201
def __init__(self): super(DataRequest, self).__init__() self.service_url = current_app.config["SERVICE_URL"] self.operator_url = current_app.config[ "OPERATOR_URL"] # TODO: Where do we really get this? self.helpers = Helpers(current_app.config)
class DataRequest(Resource): def __init__(self): super(DataRequest, self).__init__() self.service_url = current_app.config["SERVICE_URL"] self.operator_url = current_app.config[ "OPERATOR_URL"] # TODO: Where do we really get this? self.helpers = Helpers(current_app.config) @error_handler @api_logging def get(self): sq.task("Fetch PoP from authorization header") authorization = request.headers["Authorization"] debug_log.info(authorization) pop_h = pop_handler( token=authorization.split(" ") [1]) # TODO: Logic to pick up PoP, this TODO needs clarification. sq.task("Fetch at field from PoP") decoded_pop_token = loads(pop_h.get_decoded_token()) debug_log.info( "Token verified state should be False here, it is: {}".format( pop_h.verified)) debug_log.info(type(decoded_pop_token)) debug_log.info(dumps(decoded_pop_token, indent=2)) sq.task("Decode auth_token from PoP and get cr_id.") token = decoded_pop_token["at"]["auth_token"] jws_holder = jwt.JWS() jws_holder.deserialize(raw_jws=token) auth_token_payload = loads(jws_holder.__dict__["objects"]["payload"]) debug_log.info( "We got auth_token_payload: {}".format(auth_token_payload)) cr_id = auth_token_payload["pi_id"] debug_log.info( "We got cr_id {} from auth_token_payload.".format(cr_id)) sq.task("Fetch surrogate_id with cr_id") surrogate_id = self.helpers.get_surrogate_from_cr_id(cr_id) sq.task("Verify CR") cr = self.helpers.validate_cr(cr_id, surrogate_id) pop_key = cr["cr"]["role_specific_part"]["pop_key"] pop_key = jwk.JWK(**pop_key) token_issuer_key = cr["cr"]["role_specific_part"]["token_issuer_key"] token_issuer_key = jwk.JWK(**token_issuer_key) sq.task("Validate auth token") auth_token = jwt.JWT(jwt=token, key=token_issuer_key) debug_log.info( "Following auth_token claims successfully verified with token_issuer_key: {}" .format(auth_token.claims)) sq.task("Validate Request(PoP token)") pop_h = pop_handler(token=authorization.split(" ")[1], key=pop_key) decoded_pop_token = loads(pop_h.get_decoded_token( )) # This step affects verified state of object. debug_log.info( "Token verified state should be True here, it is: {}".format( pop_h.verified)) # Validate Request if pop_h.verified is False: raise ValueError("Request verification failed.") try: sq.task("Intropection") status_of_last_csr = self.helpers.introspection( cr_id, self.operator_url) if status_of_last_csr == "Active": # Process request sq.task("Return requested data.") # This is where the data requested gets fetched and returned. return { "Some test data": "like so", "and it continues": "like so!" } else: # TODO Write somewhere that this returns status of last csr source has verified to Sink debug_log.info( "Status of last csr is: {}".format(status_of_last_csr)) return { "error message is": "appropriate.", "csr_status": status_of_last_csr } except LookupError as e: debug_log.exception(e) e.message = "Introspection Failed." raise e
class GenerateSurrogateId(Resource): def __init__(self): super(GenerateSurrogateId, self).__init__() keysize = current_app.config["KEYSIZE"] cert_key_path = current_app.config["CERT_KEY_PATH"] self.helpers = Helpers(current_app.config) self.service_key = self.helpers.get_key() self.is_sink = current_app.config["IS_SINK"] self.is_source = current_app.config["IS_SOURCE"] self.service_id = current_app.config["SERVICE_ID"] self.service_url = current_app.config["SERVICE_URL"] self.operator_url = current_app.config["OPERATOR_URL"] self.lock_wait_time = current_app.config["LOCK_WAIT_TIME"] @timeme @error_handler @api_logging def post(self): try: # TODO: Verify this requests comes from Service Mockup(Is this our responsibility?) # This is now the point we want to double check that similar flow is not going on already for said user. user_id = request.json["user_id"] operator_id = request.json["operator_id"] sq.task("Checking if user_id is locked already.") user_is_locked = self.helpers.check_lock(user_id) if user_is_locked: time.sleep(self.lock_wait_time) user_is_locked = self.helpers.check_lock(user_id) if user_is_locked: raise DetailedHTTPException(status=503, detail={"msg": "Another SLR linking is in process, please try again once " "linking is over"}, title="User_id locked for SLR creation.") else: sq.task("Locking user_id.") self.helpers.lock_user(user_id) sq.task("Generate surrogate_id.") # TODO: Some logic to surrogate_id's? # surrogate_id is meant to be unique between operator and service. surrogate_id = sha256("{}_{}_{}".format(self.service_id, user_id, operator_id)).hexdigest() # Store surrogate_id to database self.helpers.add_surrogate_id_to_user_id(user_id, surrogate_id) sq.send_to("Service_Mockup", "Send surrogate_id to Service_Mockup") content_json = {"surrogate_id": surrogate_id} return content_json, 201 except DetailedHTTPException as e: debug_log.exception(e) self.helpers.delete_session(user=user_id) e.trace = traceback.format_exc(limit=100).splitlines() raise e except Exception as e: debug_log.exception(e) self.helpers.delete_session(user=user_id) raise DetailedHTTPException(exception=e, detail="Something failed in generating and delivering Surrogate_ID.", trace=traceback.format_exc(limit=100).splitlines())
class StoreSLR(Resource): def __init__(self): super(StoreSLR, self).__init__() config = current_app.config keysize = config["KEYSIZE"] cert_key_path = config["CERT_KEY_PATH"] self.helpers = Helpers(config) self.service_key = self.helpers.get_key() self.protti = self.service_key["prot"] self.headeri = self.service_key["header"] self.service_url = config["SERVICE_URL"] self.operator_url = config["OPERATOR_URL"] @timeme @error_handler @api_logging def post(self): def decode_payload(payload): sq.task("Fix possible incorrect padding in payload") payload += '=' * (-len(payload) % 4) # Fix incorrect padding of base64 string. debug_log.info("After padding fix :{}".format(payload)) sq.task("Decode SLR payload and store it into object") debug_log.info(payload.encode()) content = decode(payload.encode()) sq.task("Load decoded payload as python dict") payload = loads(content.decode("utf-8")) debug_log.info("Decoded SLR payload:") debug_log.info(type(payload)) debug_log.info(dumps(payload, indent=2)) return payload try: sq.task("Load SLR to object") slr = request.json["slr"] debug_log.info("SLR STORE:\n", slr) sq.task("Load slr payload as object") payload = slr["payload"] debug_log.info("Before padding fix:{}".format(payload)) payload = decode_payload(payload) sq.task("Fetch surrogate_id from decoded SLR payload") surrogate_id = payload["surrogate_id"].encode() sq.task("Load code from json payload") code = request.json["data"]["code"].encode() debug_log.info("SLR payload contained code: {}".format(code)) sq.task("Verify surrogate_id and code") debug_log.info("Surrogate {} has been verified for code {}.".format(self.helpers.verifySurrogate(code, surrogate_id), code)) except Exception as e: raise DetailedHTTPException(title="Verifying Surrogate ID failed", exception=e, trace=traceback.format_exc(limit=100).splitlines()) try: sq.task("Create empty JSW object") jwssa = jws.JWS() debug_log.info("SLR Received:\n"+(dumps(slr, indent=2))) sq.task("Deserialize slr to JWS object created before") jwssa.deserialize(dumps(slr)) sq.task("Load JWK used to sign JWS from the slr payload's cr_keys field into an object") sign_key = jwk.JWK(**payload["cr_keys"][0]) sq.task("Verify SLR was signed using the key shipped with it") debug_log.info(self.helpers.verifyJWS(slr)) verify = jwssa.verify(sign_key) # Verifying changes the state of this object except Exception as e: raise DetailedHTTPException(title="Verifying JWS signature failed", exception=e, trace=traceback.format_exc(limit=100).splitlines()) try: sq.task("Fix possible serialization errors in JWS") faulty_JSON = loads(jwssa.serialize(compact=False)) # For some reason serialization messes up "header" from "header": {} to "header": "{}" faulty_JSON["header"] = faulty_JSON["header"] sq.task("Add our signature in the JWS") key = jwk.JWK(**self.service_key["key"]) jwssa.add_signature(key, header=dumps(self.headeri), protected=dumps(self.protti)) sq.task("Fix possible header errors") fixed = header_fix(loads(jwssa.serialize(compact=False))) debug_log.info("{}\n{}\n{}".format("Verified and Signed Signature:\n", dumps(fixed, indent=3), "\n###### END OF SIGNATURE #######")) sq.task("Create template for verifying JWS at Operator_Components") req = {"data": {"code": code}, "slr": fixed} debug_log.info(dumps(req, indent=2)) except Exception as e: raise DetailedHTTPException(exception=e, title="JWS fix and subsequent signing of JWS with out key failed.", trace=traceback.format_exc(limit=100).splitlines()) sq.send_to("Operator_Components Mgmnt", "Verify SLR(JWS)") endpoint = "/api/1.3/slr/verify" result = post("{}{}".format(self.operator_url, endpoint), json=req) debug_log.info("Sent SLR to Operator for verification, results:") debug_log.info("status code:{}\nreason: {}\ncontent: {}".format(result.status_code, result.reason, result.content)) if result.ok: sq.task("Store following SLR into db") store = loads(result.text) slr_store = loads(result.text)["data"]["slr"] ssr_store = loads(result.text)["data"]["ssr"] debug_log.debug("Storing following SLR and SSR:") debug_log.debug(dumps(slr_store, indent=2)) debug_log.debug(dumps(ssr_store, indent=2)) payload = decode_payload(slr_store["attributes"]["payload"]) if surrogate_id == payload["surrogate_id"]: self.helpers.store_slr_JSON(json=slr_store, slr_id=payload["link_id"], surrogate_id=payload["surrogate_id"]) self.helpers.store_ssr_JSON(json=ssr_store) endpoint = "/api/1.3/slr/store_slr" debug_log.info("Posting SLR for storage in Service Mockup") result = post("{}{}".format(self.service_url, endpoint), json=store) # Send copy to Service_Components # TODO: incase this fails we should try again. else: raise DetailedHTTPException(status=500, detail={ "msg": "Surrogate id mismatch", "surrogate id's didn't match between requests.": loads(result.text)}, title=result.reason) else: raise DetailedHTTPException(status=result.status_code, detail={"msg": "Something went wrong while verifying SLR with Operator_SLR.", "Error from Operator_SLR": loads(result.text)}, title=result.reason) return store, 201 @timeme @error_handler @api_logging def get(self): # Fancy but only used for testing. Should be disabled/removed in production. sq.task("Debugging endpoint, fetch SLR's from db and return") jsons = {"jsons": {}} for storage_row in self.helpers.query_db("select * from storage;"): debug_log.info(storage_row["json"]) jsons["jsons"][storage_row["surrogate_id"]] = loads(storage_row["json"]) sq.reply_to("Operator_Components Mgmnt", "Return SLR's from db") return jsons
def __init__(self): super(StoreSSR, self).__init__() config = current_app.config self.helpers = Helpers(config) self.service_url = config["SERVICE_URL"]
def __init__(self): super(DataFlow, self).__init__() self.service_url = current_app.config["SERVICE_URL"] self.operator_url = current_app.config["OPERATOR_URL"] self.helpers = Helpers(current_app.config)
class DataFlow(Resource): def __init__(self): super(DataFlow, self).__init__() self.service_url = current_app.config["SERVICE_URL"] self.operator_url = current_app.config["OPERATOR_URL"] self.helpers = Helpers(current_app.config) @error_handler @api_logging def post(self): # TODO Make this a GET, is this valid anymore? def renew_token(operator_url, record_id): sq.task("Renewing Auth Token.") token = requests.get("{}/api/1.3/cr/auth_token/{}".format( operator_url, record_id)) # TODO Get api path from some config? debug_log.info("{}, {}, {}, {}".format(token.url, token.reason, token.status_code, token.text)) store_dict = {cr_id: dumps(loads(token.text.encode()))} self.helpers.storeToken(store_dict) def fetch_data_request_urls(): params = request.json debug_log.info(params) debug_log.info(request.json) user_id = params["user_id"] cr_id = params["cr_id"] rs_id = params["rs_id"] sq.task("Get data_set_id from POST json") data_set_id = request.args.get("dataset_id", None) debug_log.info( "data_set_id is ({}), cr_id is ({}), user_id ({}) and rs_id ({})" .format(data_set_id, cr_id, user_id, rs_id)) sq.task("Create request") req = {"we want": "data"} sq.task("Validate CR") cr = self.helpers.validate_cr(cr_id, surrogate_id=user_id) sq.task("Validate Request from UI") distribution_urls = self.helpers.validate_request_from_ui( cr, data_set_id, rs_id) # Fetch data request urls # Data request urls fetched. debug_log.info("Data request urls fetched.") return cr_id, cr, distribution_urls cr_id, cr, distribution_urls = fetch_data_request_urls() sq.task("Validate Authorisation Token") surrogate_id = cr["cr"]["common_part"]["surrogate_id"] our_key = self.helpers.get_key() our_key_pub = our_key["pub"] tries = 3 # TODO: Get this from config while True: try: aud = self.helpers.validate_authorization_token( cr_id, surrogate_id, our_key_pub) break except ValueError as e: debug_log.exception(e) renew_token(self.operator_url, cr_id) if tries == 0: raise EnvironmentError( "Auth token validation failed and retry counter exceeded." ) tries -= 1 except TypeError as e: debug_log.exception(e) raise EnvironmentError("Token used too soon, halting.") # Most verifying and checking below is done in the validate_authorization_token function by jwcrypto # Fetch Authorisation Token related to CR from data storage by rs_id (cr_id?) # Check Integrity ( Signed by operator, Operator's public key can be found from SLR) # Check "Issued" timestamp # Check "Not Before" timestamp # Check "Not After" timestamp # Check that "sub" contains correct public key(Our key.) # OPT: Token expired # Get new Authorization token, start again from validation. # TODO: Make these steps work as functions that call the next step. # Check URL patterns in "aud" field # Check that fetched distribution urls can be found from "aud" field # Token validated debug_log.info("Auth Token Validated.") # With these two steps Sink has verified that it's allowed to make request. # Construct request sq.task("Construct request") # Select request URL from "aud" field # Add Authorisation Token to request # Request constructed. # Sign request # Fetch private key pair of public key specified in Authorisation Token's "sub" field. # Sign with fetched private key sq.task("Fetch key used to sign request") our_key_full = jwk.JWK() our_key_full.import_key(**our_key["key"]) # Add signature to request # Request signed. # Request created. sq.send_to("Service_Components Mgmnt (Source)", "Data Request (PoP stuff)") # Make Data Request data = [] for url in distribution_urls: req = requests.get(url, auth=SignedRequest(token=aud, sign_method=True, sign_path=True, key=our_key_full, protected=dumps( our_key["prot"]))) if req.ok: data.append(loads(req.content)) debug_log.info( "Made data request and received following data from Source: \n{}". format(dumps(loads(req.content), indent=2))) return {"response_data": data}