def claims_ser(val, sformat="urlencoded", lev=0): # everything in c_extension if isinstance(val, six.string_types): item = val elif isinstance(val, list): item = val[0] else: item = val if isinstance(item, Message): return item.serialize(method=sformat, lev=lev + 1) if sformat == "urlencoded": res = urllib.urlencode(item) elif sformat == "json": if lev: res = item else: res = json.dumps(item) elif sformat == "dict": if isinstance(item, dict): res = item else: raise MessageException("Wrong type: %s" % type(item)) else: raise PyoidcError("Unknown sformat: %s" % sformat, val) return res
def complete(self, state): """ Do the access token request, the last step in a code flow. If Implicit flow was used then this method is never used. """ args = {"redirect_uri": self.redirect_uris[0]} if "password" in self.consumer_config and self.consumer_config[ "password"]: logger.info("basic auth") http_args = {"password": self.consumer_config["password"]} elif self.client_secret: logger.info("request_body auth") http_args = {} args.update({ "client_secret": self.client_secret, "client_id": self.client_id, "secret_type": self.secret_type }) else: raise PyoidcError("Nothing to authenticate with") resp = self.do_access_token_request(state=state, request_args=args, http_args=http_args) logger.info("Access Token Response: %s" % sanitize(resp)) if resp.type() == "ErrorResponse": raise TokenError(resp.error, resp) # self._backup(self.sdb["seed:%s" % _cli.seed]) self._backup(state) return resp
def provider_config(self, issuer, keys=True, endpoints=True, response_cls=ASConfigurationResponse, serv_pattern=OIDCONF_PATTERN): if issuer.endswith("/"): _issuer = issuer[:-1] else: _issuer = issuer url = serv_pattern % _issuer pcr = None r = self.http_request(url) if self.events: self.events.store('HTTP response header', r.headers) if r.status_code == 200: pcr = response_cls().from_json(r.text) elif r.status_code == 302: while r.status_code == 302: r = self.http_request(r.headers["location"]) if r.status_code == 200: pcr = response_cls().from_json(r.text) break if pcr is None: raise PyoidcError("Trying '%s', status %s" % (url, r.status_code)) self.handle_provider_config(pcr, issuer, keys, endpoints) return pcr
def handle_registration_info(self, response): if response.status_code in SUCCESSFUL: resp = ClientInfoResponse().deserialize(response.text, "json") self.store_response(resp, response.text) self.store_registration_info(resp) else: resp = ErrorResponse().deserialize(response.text, "json") try: resp.verify() self.store_response(resp, response.text) except Exception: raise PyoidcError('Registration failed: {}'.format( response.text)) return resp
def msg_ser(inst, sformat, lev=0): if sformat in ["urlencoded", "json"]: if isinstance(inst, dict) or isinstance(inst, Message): res = inst.serialize(sformat, lev) else: res = inst elif sformat == "dict": if isinstance(inst, Message): res = inst.serialize(sformat, lev) elif isinstance(inst, dict): res = inst elif isinstance(inst, six.string_types): # Iff ID Token res = inst else: raise MessageException("Wrong type: %s" % type(inst)) else: raise PyoidcError("Unknown sformat", inst) return res
def handle_provider_config(self, pcr, issuer, keys=True, endpoints=True): """ Deal with Provider Config Response :param pcr: The ProviderConfigResponse instance :param issuer: The one I thought should be the issuer of the config :param keys: Should I deal with keys :param endpoints: Should I deal with endpoints, that is store them as attributes in self. """ if "issuer" in pcr: _pcr_issuer = pcr["issuer"] if pcr["issuer"].endswith("/"): if issuer.endswith("/"): _issuer = issuer else: _issuer = issuer + "/" else: if issuer.endswith("/"): _issuer = issuer[:-1] else: _issuer = issuer if not self.allow.get("issuer_mismatch", False) and _issuer != _pcr_issuer: raise PyoidcError( "provider info issuer mismatch '%s' != '%s'" % (_issuer, _pcr_issuer)) self.provider_info = pcr else: _pcr_issuer = issuer if endpoints: for key, val in pcr.items(): if key.endswith("_endpoint"): setattr(self, key, val) if keys: if self.keyjar is None: self.keyjar = KeyJar() self.keyjar.load_keys(pcr, _pcr_issuer)
def begin(self, scope="", response_type="", use_nonce=False, path="", **kwargs): """ Begin the OIDC flow :param scope: Defines which user info claims is wanted :param response_type: Controls the parameters returned in the response from the Authorization Endpoint :param use_nonce: If not implicit flow nonce is optional. This defines if it should be used anyway. :param path: The path part of the redirect URL :return: A 2-tuple, session identifier and URL to which the user should be redirected """ _log_info = logger.info if self.debug: _log_info("- begin -") _page = self.consumer_config["authz_page"] if not path.endswith("/"): if _page.startswith("/"): self.redirect_uris = [path + _page] else: self.redirect_uris = ["%s/%s" % (path, _page)] else: if _page.startswith("/"): self.redirect_uris = [path + _page[1:]] else: self.redirect_uris = ["%s/%s" % (path, _page)] # Put myself in the dictionary of sessions, keyed on session-id if not self.seed: self.seed = rndstr() if not scope: scope = self.consumer_config["scope"] if not response_type: response_type = self.consumer_config["response_type"] sid = stateID(path, self.seed) self.grant[sid] = Grant(seed=self.seed) self._backup(sid) self.sdb["seed:%s" % self.seed] = sid args = { "client_id": self.client_id, "state": sid, "response_type": response_type, "scope": scope, } # nonce is REQUIRED in implicit flow, # OPTIONAL on code flow. if "token" in response_type or use_nonce: args["nonce"] = rndstr(12) self.state2nonce[sid] = args['nonce'] if "max_age" in self.consumer_config: args["max_age"] = self.consumer_config["max_age"] _claims = None if "user_info" in self.consumer_config: _claims = ClaimsRequest(userinfo=Claims( **self.consumer_config["user_info"])) if "id_token" in self.consumer_config: if _claims: _claims["id_token"] = Claims( **self.consumer_config["id_token"]) else: _claims = ClaimsRequest(id_token=Claims( **self.consumer_config["id_token"])) if _claims: args["claims"] = _claims if "request_method" in self.consumer_config: areq = self.construct_AuthorizationRequest(request_args=args, extra_args=None, request_param="request") if self.consumer_config["request_method"] == "file": id_request = areq["request"] del areq["request"] _filedir = self.consumer_config["temp_dir"] _webpath = self.consumer_config["temp_path"] _name = rndstr(10) filename = os.path.join(_filedir, _name) while os.path.exists(filename): _name = rndstr(10) filename = os.path.join(_filedir, _name) fid = open(filename, mode="w") fid.write(id_request) fid.close() _webname = "%s%s/%s" % (path, _webpath, _name) areq["request_uri"] = _webname self.request_uri = _webname self._backup(sid) else: if "userinfo_claims" in args: # can only be carried in an IDRequest raise PyoidcError("Need a request method") areq = self.construct_AuthorizationRequest(AuthorizationRequest, request_args=args) location = areq.request(self.authorization_endpoint) if self.debug: _log_info("Redirecting to: %s" % location) return sid, location