class CancelSlrFlow(Resource): def __init__(self): """ """ super(CancelSlrFlow, self).__init__() self.helper = Helpers(current_app.config) @error_handler @api_logging def delete(self, account_id, code): AM = get_am(current_app, request.headers) key_check = AM.verify_user_key(account_id) debug_log.info("Verifying User Key resulted: {}".format(key_check)) sq.task("Load json payload as object") js = request.json sq.task("Load account_id from database") code = js["code"] try: stored_session_from_db = self.helper.restore_session(code) except TypeError as e: debug_log.info("Failed restoring session from DB with code '{}'".format(code)) debug_log.exception(e) raise DetailedHTTPException(status=403, detail={"msg": "Invalid or expired session"}, title="Invalid session") debug_log.debug("The session data contains: {}".format(stored_session_from_db)) session_data = loads(stored_session_from_db) debug_log.debug("{} {}".format(type(stored_session_from_db), stored_session_from_db)) account_id_from_session = session_data["account_id"] if account_id_from_session == account_id: self.helper.delete_session(code) return {"msg": {"status": "deleted", "id": code}}, 200
class RegisterSurrogate(Resource): def __init__(self): super(RegisterSurrogate, self).__init__() self.app = current_app self.helpers = Helpers(self.app.config) operator_id = self.app.config["UID"] self.service_registry_handler = ServiceRegistryHandler( current_app.config["SERVICE_REGISTRY_SEARCH_DOMAIN"], current_app.config["SERVICE_REGISTRY_SEARCH_ENDPOINT"]) self.operator_key = self.helpers.get_key() self.request_timeout = self.app.config["TIMEOUT"] self.payload = \ { "version": "1.3", "link_id": "", "operator_id": operator_id, "service_id": "", "surrogate_id": "", "operator_key": self.operator_key["pub"], "cr_keys": "", "iat": 0, # Set below once we know link_id } debug_log.info("SLR payload in init is: \n{}".format( dumps(self.payload, indent=2))) self.service_registry_handler = ServiceRegistryHandler( current_app.config["SERVICE_REGISTRY_SEARCH_DOMAIN"], current_app.config["SERVICE_REGISTRY_SEARCH_ENDPOINT"]) self.am_url = current_app.config["ACCOUNT_MANAGEMENT_URL"] self.am_user = current_app.config["ACCOUNT_MANAGEMENT_USER"] self.am_password = current_app.config["ACCOUNT_MANAGEMENT_PASSWORD"] self.timeout = current_app.config["TIMEOUT"] @error_handler @api_logging def post(self): try: sq.task("Load json payload as object") js = request.json sq.task("Load account_id and service_id from database") code = js["code"] try: stored_session_from_db = self.helpers.restore_session(code) except TypeError as e: debug_log.info( "Failed restoring session from DB with code '{}'".format( code)) debug_log.exception(e) raise DetailedHTTPException( status=403, detail={"msg": "Invalid or expired session"}, title="Invalid session") debug_log.debug( "Type of session data fetched from db is: {}".format( type(stored_session_from_db))) debug_log.debug( "The session data contains: {}".format(stored_session_from_db)) session_data = loads(stored_session_from_db) debug_log.debug("{} {}".format(type(stored_session_from_db), stored_session_from_db)) account_id = session_data["account_id"] # Get Account Manager Handler AM = get_am(current_app, request.headers) key_check = AM.verify_user_key(account_id, user_key=session_data["user_key"]) debug_log.info("Verifying User Key resulted: {}".format(key_check)) self.payload["service_id"] = session_data["service_id"] service_info = self.service_registry_handler.getService( self.payload["service_id"]) # TODO: Use serviceType field added into ServiceDescription service_type = service_info["serviceDescription"][ "serviceDataDescription"][0]["dataset"][0]["serviceDataType"] # Check Surrogate_ID exists. # Fill token_key try: sq.task( "Verify surrogate_id and token_key exist in the payload json" ) self.payload["surrogate_id"] = js["surrogate_id"] #self.payload["token_key"] = {"key": token_key} if service_type == "input" or service_type == "both": sq.task( "Store surrogate_id and keys for CR steps later on.") token_key = js[ "token_key"] # Todo: source has no need to send this, make the difference. service_keys = { "token_key": token_key, "pop_key": token_key } self.helpers.store_service_key_json( kid=token_key["kid"], surrogate_id=js["surrogate_id"], key_json=service_keys, service_id=service_info["id"]) except Exception as e: debug_log.exception(e) if "code" in locals(): self.helper.delete_session(code) raise DetailedHTTPException( exception=e, detail={ "msg": "Received Invalid JSON that may not contain surrogate_id", "json": js }) # Create template # TODO: Currently you can generate endlessly new slr even if one exists already if service_type == "input" or service_type == "both": result = AM.init_slr(code, pop_key=token_key) else: result = AM.init_slr(code) self.payload["link_id"] = result self.payload["iat"] = int(time.time()) sq.task("Fill template for Account Manager") template = { "code": code, "data": { "type": "ServiceLinkRecord", "attributes": self.payload } } debug_log.info("########### Template for Account Manager #") debug_log.info(dumps(template, indent=2)) debug_log.info("########################################") sq.send_to("Account Manager", "Sign SLR at Account Manager") try: reply = AM.sign_slr(template, account_id) except AttributeError as e: self.helpers.delete_session(code) raise DetailedHTTPException( status=502, title= "It would seem initiating Account Manager Handler has failed.", detail="Account Manager might be down or unresponsive.", trace=traceback.format_exc(limit=100).splitlines()) debug_log.info(dumps(reply, indent=2)) # Parse JSON form Account Manager to format Service_Mgmnt understands. try: req = { "data": { "code": code, }, "slr": reply["data"]["attributes"] } debug_log.info( "SLR in format sent to Service Mgmnt: {}".format( dumps(req, indent=2))) except Exception as e: raise DetailedHTTPException( exception=e, detail="Parsing JSON form Account Manager " "to format Service_Mgmnt understands has failed.", trace=traceback.format_exc(limit=100).splitlines()) try: sq.send_to( "Service_Components Mgmnt", "Send created and signed SLR to Service_Components Mgmnt") endpoint = "/api/1.3/slr/slr" # TODO Where do we get this endpoint? service_url = self.service_registry_handler.getService_url( self.payload["service_id"].encode()) debug_log.info("Service_ulr = {}, type: {}".format( service_url, type(service_url))) response = post("{}{}".format(service_url, endpoint), json=req, timeout=self.request_timeout) debug_log.info( "Service Mgmnt replied with status code ({})".format( response.status_code)) if not response.ok: self.helpers.delete_session(code) raise DetailedHTTPException( status=response.status_code, detail={ "Error from Service_Components Mgmnt": loads(response.text) }, title=response.reason) except DetailedHTTPException as e: raise e except Exception as e: self.helpers.delete_session(code) raise DetailedHTTPException( exception=e, detail="Sending SLR to service has failed", trace=traceback.format_exc(limit=100).splitlines()) except DetailedHTTPException as e: if "code" in locals(): self.helpers.delete_session(code) raise e except Exception as e: if "code" in locals(): self.helpers.delete_session(code) raise DetailedHTTPException( title="Creation of SLR has failed.", exception=e, trace=traceback.format_exc(limit=100).splitlines()) # SLR is made at this point and returned to the Service Mgmnt, session can be deleted. if "code" in locals(): self.helpers.delete_session(code) return loads(response.text), 201
class StartSlrFlow(Resource): def __init__(self): """ """ super(StartSlrFlow, self).__init__() self.service_registry_handler = ServiceRegistryHandler(current_app.config["SERVICE_REGISTRY_SEARCH_DOMAIN"], current_app.config["SERVICE_REGISTRY_SEARCH_ENDPOINT"]) self.request_timeout = current_app.config["TIMEOUT"] self.uid = current_app.config["UID"] self.return_url = current_app.config["RETURN_URL"] self.helper = Helpers(current_app.config) self.store_session = self.helper.store_session @error_handler @api_logging def get(self, account_id, service_id): """ :param account_id: Account Manager user id :param service_id: Service id as in Service Registry """ debug_log.info("#### Request to start SLR flow with parameters: account_id ({}), service_id ({})" .format(account_id, service_id)) try: AM = get_am(current_app, request.headers) key_check = AM.verify_user_key(account_id) debug_log.info("Verifying User Key resulted: {}".format(key_check)) # Check Active SLR for this account/service pair doesn't exist AM.check_for_existing_slr(service_id, account_id) # We need to store some session information for later parts of flow. session_information = {} sq.task("Fetch service address from Service Registry") service_json = self.service_registry_handler.getService(service_id) service_domain = service_json["serviceInstance"][0]["loginDomain"] # Domain to Login of Service service_access_uri = service_json["serviceInstance"][0]["serviceAccessEndPoint"]["serviceAccessURI"] service_login_uri = service_json["serviceInstance"][0]["loginUri"] sq.task("Generate code for session") code = str(guid()) debug_log.info("Session information contains: code {}, account id {} and service_id {}" .format(code, account_id, service_id)) sq.task("Store session_information to database") session_information[code] = {"account_id": account_id, "service_id": service_id, "user_key": request.headers["Api-Key-User"]} self.store_session(session_information) service_endpoint = "{}{}{}".format(service_domain, service_access_uri, service_login_uri) service_query = "?code={}&operator_id={}&return_url={}&linkingFrom={}".format( # TODO: Get return url from somewhere code, self.uid, urlsafe_b64encode(self.return_url), "Operator") debug_log.info("Redirect url with parameters:\n{}{}\nCode contains: {}".format(service_endpoint, service_query, code)) sq.send_to("UI(Operator)", "Redirect user to Service Mockup login") response = make_response(redirect(service_endpoint+service_query)) return response except DetailedHTTPException as e: debug_log.exception(e) if "code" in locals(): self.helper.delete_session(code) raise DetailedHTTPException(exception=e, title="SLR registration failed.", status=500, detail="Something failed during creation of SLR.", trace=traceback.format_exc(limit=100).splitlines()) except Exception as e: debug_log.exception(e) if "code" in locals(): self.helper.delete_session(code) raise DetailedHTTPException(status=500, title="Something went really wrong during SLR registration.", detail="Error: {}".format(repr(e)), exception=e, trace=traceback.format_exc(limit=100).splitlines())
class LinkingUi(Resource): def __init__(self): super(LinkingUi, self).__init__() self.helper = Helpers(current_app.config) self.account_url = current_app.config["ACCOUNT_MANAGEMENT_URL"] self.operator_id = current_app.config["OPERATOR_UID"] self.parser = reqparse.RequestParser() self.parser.add_argument('surrogate_id', type=str, help='Surrogate_id from a service.') self.parser.add_argument('service_id', type=str, help='ID of linking service.') self.parser.add_argument('username', type=str, help='Username for MyDataAccount') self.parser.add_argument('pword', type=str, help='Password for MyDataAccount') self.parser.add_argument('return_url', type=str, help='Url safe Base64 coded return url.') self.parser.add_argument('linkingFrom', type=str, help='Origin of the linking request(?)') self.store_session = self.helper.store_session self.service_registry_handler = ServiceRegistryHandler( current_app.config["SERVICE_REGISTRY_SEARCH_DOMAIN"], current_app.config["SERVICE_REGISTRY_SEARCH_ENDPOINT"]) @error_handler @api_logging def get(self): args = self.parser.parse_args() args["operator_id"] = self.operator_id args["provider"] = args["service_id"] # Check headers for Account API key # If key is n # TODO: Use template file or get this from somewhere. tmpl_str = ''' <html><header></header><body> <form class="form-horizontal" action="" method="POST"> <fieldset> <legend>Link {{provider}} with Operator({{ operator_id }})</legend> <div class="form-group"> <div class="col-lg-10 col-lg-offset-1"> Username:<input name="username" id="username"></input><br> Password:<input name="pword" id="pword"></input> <button type="reset" class="btn btn-default">Cancel</button> <button type="submit" class="btn btn-primary">Submit</button> </div> </div> </fieldset> <div {{ fromOperator }}> <p> By linking service to Operator, you agree to the <a href="#LinkToToS">Terms of Service</a></p> </div> <input type="hidden" name="surrogate_id" value="{{ surrogate_id }}"> <input type="hidden" name="service_id" value="{{ service_id }}"> <input type="hidden" name="return_url" value="{{ return_url }}"> <input type="hidden" name="linkingFrom" value="{{ linkingFrom }}"> </form> </body></html> ''' # Render Login template response = make_response(render_template_string(tmpl_str, **args), 200) return response @error_handler @api_logging def post(self): args = self.parser.parse_args() def get_api_key(account_url=self.account_url + "account/api/v1.3/", user=None, password=None, endpoint="external/auth/user/"): debug_log.info( "\nFetching Account Key for account '{}' from endpoint: {}". format(user + ":" + password, account_url + endpoint)) api_json = get(account_url + endpoint, auth=(user, password)) #debug_log.info("Received following key:\n {}".format(api_json)) if api_json.ok: return loads(api_json.text) else: raise DetailedHTTPException( title="Authentication to Account failed.", status=403) # Check Account is valid account, this is dummy UI, this is dumm test. account_info = get_api_key(user=args["username"], password=args["pword"]) account_id = account_info["account_id"] account_api_key = account_info["Api-Key-User"] # Initialize all common variables surrogate_id = args["surrogate_id"] service_id = args["service_id"] return_url = args["return_url"] # Generate Code for session code = str(guid()) debug_log.info( "Session information contains: code {}, account id {} and service_id {}" .format(code, account_id, service_id)) debug_log.info("Store session_information to database") session_information = { code: { "account_id": account_id, "service_id": service_id, "user_key": account_api_key } } self.store_session(session_information) try: # Make request to register surrogate_id data = { "code": code, "operator_id": self.operator_id, "return_url": return_url, "surrogate_id": surrogate_id, } # Fetch service information: service_json = self.service_registry_handler.getService(service_id) service_domain = service_json["serviceInstance"][0][ "domain"] # Domain to Login of Service service_access_uri = service_json["serviceInstance"][0][ "serviceAccessEndPoint"]["serviceAccessURI"] service_linking_uri = "/slr/linking" service_url = service_domain + service_access_uri + service_linking_uri # Initiate Service Link Process debug_log.info("Sending linking request to Service at: {}".format( service_url)) linking_result = post(service_url, json=data) debug_log.debug("Service Linking resulted in:\n {}\n {}".format( linking_result.status_code, linking_result.text)) # If SLR was created success fully load it as a dictionary, on errors we delete session. if linking_result.ok: reply_json = loads(linking_result.text) else: self.helper.delete_session(code) raise DetailedHTTPException( title=linking_result.reason, status=linking_result.status_code, detail={"msg": linking_result.text}) debug_log.info( "Encoding json as reply to ui: \n{}".format(reply_json)) if isinstance(reply_json, dict): reply_json = dumps(reply_json) self.helper.delete_session(code) return redirect("{}?results={}".format( decode64(args["return_url"]), encode64(reply_json)), code=302) except DetailedHTTPException as e: self.helper.delete_session(code) raise e except Exception as e: self.helper.delete_session(code) raise DetailedHTTPException( status=500, exception=e, title="Something went wrong during service linking, try again." )