def handle_response(self, response, issuer, func, response_cls): """ Handle a request response. Depending on which type of response it is different functions *func* will be used to handle it. If something went wrong an exception will be raised. :param response: A requests.request response :param issuer: who was the request sent to :param func: A function to use for handling a correct response :param response_cls: The response should match this class """ err_msg = 'Got error response: {}' unk_msg = 'Unknown response: {}' if response.status_code in [200, 201]: resp = response_cls().deserialize(response.text, "json") # Some implementations sends back a 200 with an error message inside if resp.verify(): # got a proper response func(resp, issuer) else: resp = ErrorResponse().deserialize(response.text, "json") if resp.verify(): logger.error(err_msg.format(sanitize(resp.to_json()))) if self.events: self.events.store('protocol response', resp) raise RegistrationError(resp.to_dict()) else: # Something else logger.error(unk_msg.format(sanitize(response.text))) raise RegistrationError(response.text) else: try: resp = ErrorResponse().deserialize(response.text, "json") except _decode_err: logger.error(unk_msg.format(sanitize(response.text))) raise RegistrationError(response.text) if resp.verify(): logger.error(err_msg.format(sanitize(resp.to_json()))) if self.events: self.events.store('protocol response', resp) raise RegistrationError(resp.to_dict()) else: # Something else logger.error(unk_msg.format(sanitize(response.text))) raise RegistrationError(response.text)
def handle_registration_info(self, response): err_msg = 'Got error response: {}' unk_msg = 'Unknown response: {}' if response.status_code in [200, 201]: resp = RegistrationResponse().deserialize(response.text, "json") # Some implementations sends back a 200 with an error message inside if resp.verify(): # got a proper registration response resp = self.get_metadata_statement(resp) if resp is None: # No metadata statement that I can use raise RegistrationError('No trusted metadata') self.store_response(resp, response.text) self.store_registration_info(resp) else: resp = ErrorResponse().deserialize(response.text, "json") if resp.verify(): logger.error(err_msg.format(sanitize(resp.to_json()))) if self.events: self.events.store('protocol response', resp) raise RegistrationError(resp.to_dict()) else: # Something else logger.error(unk_msg.format(sanitize(response.text))) raise RegistrationError(response.text) else: try: resp = ErrorResponse().deserialize(response.text, "json") except _decode_err: logger.error(unk_msg.format(sanitize(response.text))) raise RegistrationError(response.text) if resp.verify(): logger.error(err_msg.format(sanitize(resp.to_json()))) if self.events: self.events.store('protocol response', resp) raise RegistrationError(resp.to_dict()) else: # Something else logger.error(unk_msg.format(sanitize(response.text))) raise RegistrationError(response.text) return resp
def provider_config(self, issuer, keys=True, endpoints=True, response_cls=ProviderConfigurationResponse, serv_pattern=OIDCONF_PATTERN): """ The high level method that should be used, by an application, to get the provider info. :param issuer: The provider/issuer ID :param keys: Whether I should store the keys I get back form the OP :type keys: Boolean :param endpoints: Should I deal with endpoints; that is store them as attributes in self. :param response_cls: A class to store the response information in :param serv_pattern: A string pattern used to build the query URL. :return: A :py:class:`fedoidc.ProviderConfigurationResponse` instance """ if issuer.endswith("/"): _issuer = issuer[:-1] else: _issuer = issuer url = serv_pattern % _issuer pcr = None r = self.http_request(url, allow_redirects=True) if r.status_code == 200: try: pcr = response_cls().from_json(r.text) except: _err_txt = "Faulty provider config response: {}".format(r.text) logger.error(sanitize(_err_txt)) raise ParseError(_err_txt) if 'metadata_statements' not in pcr: if 'metadata_statement_uris' not in pcr: # Talking to a federation unaware OP self.store_response(pcr, r.text) self.handle_provider_config(pcr, issuer, keys, endpoints) return pcr # logger.debug("Provider info: %s" % sanitize(pcr)) if pcr is None: raise CommunicationError("Trying '%s', status %s" % (url, r.status_code)) # 3 possible outcomes # a) No usable provider info -> Exception # b) Exactly one possible provider info to use # c) 2 or more usable provider info responses try: self.handle_response(r, _issuer, self.parse_federation_provider_info, ProviderConfigurationResponse) except RegistrationError as err: raise if self.provider_federations: return self.chose_provider_federation(_issuer) else: # Otherwise there should be exactly one metadata statement I return self.provider_info