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
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