Example #1
0
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"]
Example #3
0
 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"]
Example #4
0
    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"]
Example #5
0
    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")
Example #6
0
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)
Example #7
0
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
Example #8
0
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
Example #10
0
 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)
Example #11
0
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
Example #12
0
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())
Example #13
0
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
Example #14
0
 def __init__(self):
     super(StoreSSR, self).__init__()
     config = current_app.config
     self.helpers = Helpers(config)
     self.service_url = config["SERVICE_URL"]
Example #15
0
 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)
Example #16
0
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}